瀏覽代碼

Merge pull request #137 from lolgzs/master

fix bugs
Nicolas Petton 13 年之前
父節點
當前提交
40c23ee17f
共有 9 個文件被更改,包括 2973 次插入2357 次删除
  1. 438 438
      js/IDE.deploy.js
  2. 550 295
      js/IDE.js
  3. 2 2
      js/Kernel-Collections.deploy.js
  4. 4 4
      js/Kernel-Collections.js
  5. 430 279
      js/Kernel-Tests.deploy.js
  6. 596 395
      js/Kernel-Tests.js
  7. 358 357
      st/IDE.st
  8. 5 1
      st/Kernel-Collections.st
  9. 590 586
      st/Kernel-Tests.st

文件差異過大導致無法顯示
+ 438 - 438
js/IDE.deploy.js


文件差異過大導致無法顯示
+ 550 - 295
js/IDE.js


+ 2 - 2
js/Kernel-Collections.deploy.js

@@ -726,9 +726,9 @@ smalltalk.addMethod(
 unescape('_ifEmpty_'),
 smalltalk.method({
 selector: unescape('ifEmpty%3A'),
-fn: function (aBlock) {
+fn: function (aBlock){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_isEmpty", []), "_ifTrue_", [aBlock]);
+return ((($receiver = smalltalk.send(self, "_isEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aBlock, "_value", []);})() : (function(){return self;})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(aBlock, "_value", []);}), (function(){return self;})]));
 return self;}
 }),
 smalltalk.Collection);

+ 4 - 4
js/Kernel-Collections.js

@@ -1037,13 +1037,13 @@ unescape('_ifEmpty_'),
 smalltalk.method({
 selector: unescape('ifEmpty%3A'),
 category: 'testing',
-fn: function (aBlock) {
+fn: function (aBlock){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_isEmpty", []), "_ifTrue_", [aBlock]);
+return ((($receiver = smalltalk.send(self, "_isEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aBlock, "_value", []);})() : (function(){return self;})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(aBlock, "_value", []);}), (function(){return self;})]));
 return self;},
 args: ["aBlock"],
-source: unescape('ifEmpty%3A%20aBlock%0A%09self%20isEmpty%20ifTrue%3A%20aBlock.'),
-messageSends: ["ifTrue:", "isEmpty"],
+source: unescape('ifEmpty%3A%20aBlock%0A%09%22Evaluate%20the%20given%20block%20with%20the%20receiver%20as%20argument%2C%20answering%20its%20value%20if%20the%20receiver%20is%20empty%2C%20otherwise%20answer%20the%20receiver.%20Note%20that%20the%20fact%20that%20this%20method%20returns%20its%20argument%20in%20case%20the%20receiver%20is%20not%20empty%20allows%20one%20to%20write%20expressions%20like%20the%20following%20ones%3A%20self%20classifyMethodAs%3A%20%0A%09%09%28myProtocol%20ifEmpty%3A%20%5B%27As%20yet%20unclassified%27%5D%29%22%0A%09%5E%20self%20isEmpty%20%0A%09%09ifTrue%3A%20%5B%20aBlock%20value%20%5D%0A%09%09ifFalse%3A%20%5B%20self%20%5D'),
+messageSends: ["ifTrue:ifFalse:", "isEmpty", "value"],
 referencedClasses: []
 }),
 smalltalk.Collection);

文件差異過大導致無法顯示
+ 430 - 279
js/Kernel-Tests.deploy.js


文件差異過大導致無法顯示
+ 596 - 395
js/Kernel-Tests.js


+ 358 - 357
st/IDE.st

@@ -1,185 +1,295 @@
 Smalltalk current createPackage: 'IDE' properties: #{}!
-ErrorHandler subclass: #DebugErrorHandler
-	instanceVariableNames: ''
-	category: 'IDE'!
-
-!DebugErrorHandler methodsFor: 'error handling'!
-
-handleError: anError
-	[Debugger new
-		error: anError;
-		open] on: Error do: [:error |
-			ErrorHandler new handleError: error]
-! !
-
-!DebugErrorHandler class methodsFor: 'initialization'!
-
-initialize
-	self register
-! !
-
-Widget subclass: #ClassesListNode
-	instanceVariableNames: 'browser theClass level nodes'
+Widget subclass: #TabManager
+	instanceVariableNames: 'selectedTab tabs opened ul input'
 	category: 'IDE'!
 
-!ClassesListNode methodsFor: ''!
-
-renderOn: html
-	| li cssClass |
-	cssClass := ''.
-	li := html li 
-		onClick: [self browser selectClass: self theClass]. 
-	li asJQuery html: self label.
-
-	self browser selectedClass = self theClass ifTrue:  [
-		cssClass := cssClass, ' selected'].
-
-	self theClass comment isEmpty ifFalse: [
-		cssClass := cssClass, ' commented'].
+!TabManager methodsFor: 'accessing'!
 
-	li class: cssClass.
+tabs
+    ^tabs ifNil: [tabs := Array new]
+!
 
-	self nodes do: [:each |
-		each renderOn: html]
+labelFor: aWidget
+	| label maxSize |
+	maxSize := 15.
+	label := aWidget label copyFrom: 0 to: (aWidget label size min: maxSize).
+	aWidget label size > maxSize ifTrue: [
+		label := label, '...'].
+	^label
 ! !
 
-!ClassesListNode methodsFor: 'accessing'!
-
-nodes
-	^nodes
-!
-
-theClass
-	^theClass
-!
+!TabManager methodsFor: 'actions'!
 
-theClass: aClass
-	theClass := aClass
+updateBodyMargin
+    self setBodyMargin: '#jtalk' asJQuery height
 !
 
-browser
-	^browser
+updatePosition
+    <jQuery('#jtalk').css('top', '').css('bottom', '0px')>
 !
 
-browser: aBrowser
-	browser := aBrowser
+removeBodyMargin
+    self setBodyMargin: 0
 !
 
-level
-	^level
+setBodyMargin: anInteger
+    '.jtalkBody' asJQuery css: 'margin-bottom' put: anInteger asString, 'px'
 !
 
-level: anInteger
-	level := anInteger
+onResize: aBlock
+    <jQuery('#jtalk').resizable({
+	handles: 'n', 
+	resize: aBlock,
+	minHeight: 230
+})>
 !
 
-label
-	| str |
-	str := String new writeStream.
-	self level timesRepeat: [
-		str nextPutAll: '&nbsp;&nbsp;&nbsp;&nbsp;'].
-	str nextPutAll: self theClass name.
-	^str contents
+onWindowResize: aBlock
+    <jQuery(window).resize(aBlock)>
 !
 
-getNodesFrom: aCollection
-	| children others |
-	children := #().
-	others := #().
-	aCollection do: [:each |
-		(each superclass = self theClass)
-			ifTrue: [children add: each]
-			ifFalse: [others add: each]].
-	nodes:= children collect: [:each |
-		ClassesListNode on: each browser: self browser classes: others level: self level + 1]
-! !
-
-!ClassesListNode class methodsFor: 'instance creation'!
-
-on: aClass browser: aBrowser classes: aCollection level: anInteger
-	^self new
-		theClass: aClass;
-		browser: aBrowser;
-		level: anInteger;
-		getNodesFrom: aCollection;
-		yourself
-! !
-
-Widget subclass: #ClassesList
-	instanceVariableNames: 'browser ul nodes'
-	category: 'IDE'!
-
-!ClassesList methodsFor: 'accessing'!
-
-category
-	^self browser selectedPackage
+open
+    opened ifFalse: [
+	'body' asJQuery addClass: 'jtalkBody'.
+	'#jtalk' asJQuery show.
+	ul asJQuery show.
+	self updateBodyMargin.
+	selectedTab show.
+	opened := true]
 !
 
-nodes
-	nodes ifNil: [nodes := self getNodes].
-	^nodes
+close
+    opened ifTrue: [
+	'#jtalk' asJQuery hide.
+	ul asJQuery hide.
+	selectedTab hide.
+	self removeBodyMargin.
+	'body' asJQuery removeClass: 'jtalkBody'.
+	opened := false]
 !
 
-browser
-	^browser
+newBrowserTab
+    Browser open
 !
 
-browser: aBrowser
-	browser := aBrowser
+selectTab: aWidget
+    self open.
+    selectedTab := aWidget.
+    self tabs do: [:each |
+	each hide].
+    aWidget show.
+	
+    self update
 !
 
-getNodes
-	| classes children others |
-	classes := self browser classes.
-	children := #().
-	others := #().
-	classes do: [:each |
-		(classes includes: each superclass)
-			ifFalse: [children add: each]
-			ifTrue: [others add: each]].
-	^children collect: [:each |
-		ClassesListNode on: each browser: self browser classes: others level: 0]
+closeTab: aWidget
+    self removeTab: aWidget.
+    self selectTab: self tabs last.
+    aWidget remove.
+    self update
 !
 
-resetNodes
-	nodes := nil
+search: aString
+	| searchedClass |
+	searchedClass := Smalltalk current at: aString.
+		searchedClass isClass
+			ifTrue: [Browser openOn: searchedClass]
+			ifFalse: [ReferencesBrowser search: aString]
 ! !
 
-!ClassesList methodsFor: 'rendering'!
+!TabManager methodsFor: 'adding/Removing'!
 
-renderOn: html
-	ul := html ul
-		class: 'jt_column browser classes';
-		yourself.
-	self updateNodes
+addTab: aWidget
+    self tabs add: aWidget.
+    aWidget appendToJQuery: '#jtalk' asJQuery.
+    aWidget hide
 !
 
-updateNodes
-	ul contents: [:html |
-		self nodes do: [:each |
-			each renderOn: html]]
+removeTab: aWidget
+    self tabs remove: aWidget.
+    self update
 ! !
 
-!ClassesList class methodsFor: 'instance creation'!
+!TabManager methodsFor: 'initialization'!
 
-on: aBrowser
-	^self new 
-		browser: aBrowser; 
-		yourself
+initialize
+    super initialize.
+    opened := true.
+    [:html | html div id: 'jtalk'] appendToJQuery: 'body' asJQuery.
+    'body' asJQuery 
+	addClass: 'jtalkBody'.
+    self appendToJQuery: '#jtalk' asJQuery.
+    self 
+	addTab: IDETranscript current;
+	addTab: Workspace new;
+	addTab: TestRunner new.
+    self selectTab: self tabs last.
+    self 
+	onResize: [self updateBodyMargin; updatePosition];
+	onWindowResize: [self updatePosition]
 ! !
 
-Widget subclass: #SourceArea
-	instanceVariableNames: 'editor div receiver onDoIt'
-	category: 'IDE'!
-
-!SourceArea methodsFor: 'accessing'!
+!TabManager methodsFor: 'rendering'!
 
-val
-    ^editor getValue
+renderOn: html
+	html div id: 'logo'.
+	self renderToolbarOn: html.
+	ul := html ul
+		id: 'jtalkTabs';
+		yourself.
+	self renderTabs
 !
 
-val: aString
-    editor setValue: aString
+renderTabFor: aWidget on: html
+	| li |
+	li := html li.
+	selectedTab = aWidget ifTrue: [
+	li class: 'selected'].
+	li with: [
+		html span class: 'ltab'.
+		html span
+			class: 'mtab';
+			with: [
+				aWidget canBeClosed ifTrue: [
+					html span 
+						class: 'close';
+						with: 'x';
+					onClick: [self closeTab: aWidget]].
+			html span with: (self labelFor: aWidget)].
+		html span class: 'rtab'];
+	onClick: [self selectTab: aWidget]
+!
+
+renderTabs
+	ul contents: [:html |
+	    self tabs do: [:each |
+		self renderTabFor: each on: html].
+	    html li
+		class: 'newtab';
+		with: [
+			html span class: 'ltab'.
+			html span class: 'mtab'; with: ' + '.
+			html span class: 'rtab'];
+		onClick: [self newBrowserTab]]
+!
+
+renderToolbarOn: html
+	html div 
+		id: 'jt_toolbar';
+		with: [
+			input := html input 
+				class: 'implementors';
+				yourself.
+			input onKeyPress: [:event |
+				event keyCode = 13 ifTrue: [
+				self search: input asJQuery val]].
+			html div id: 'jt_close'; onClick: [self close]]
+! !
+
+!TabManager methodsFor: 'updating'!
+
+update
+	self renderTabs
+! !
+
+TabManager class instanceVariableNames: 'current'!
+
+!TabManager class methodsFor: 'instance creation'!
+
+current
+    ^current ifNil: [current := super new]
+!
+
+new
+    self shouldNotImplement
+! !
+
+Widget subclass: #TabWidget
+	instanceVariableNames: 'div'
+	category: 'IDE'!
+
+!TabWidget methodsFor: 'accessing'!
+
+label
+    self subclassResponsibility
+! !
+
+!TabWidget methodsFor: 'actions'!
+
+open
+    TabManager current addTab: self.
+    TabManager current selectTab: self
+!
+
+show
+	div asJQuery show
+!
+
+hide
+	div asJQuery hide
+!
+
+remove
+	div asJQuery remove
+!
+
+close
+    TabManager current closeTab: self
+! !
+
+!TabWidget methodsFor: 'rendering'!
+
+renderOn: html
+	div := html div
+		class: 'jtalkTool';
+		yourself.
+	self renderTab
+!
+
+renderBoxOn: html
+!
+
+renderButtonsOn: html
+!
+
+update
+	self renderTab
+!
+
+renderTab
+	div contents: [:html |
+	    html div
+		class: 'jt_box';
+		with: [self renderBoxOn: html].
+	    html div
+		class: 'jt_buttons';
+		with: [self renderButtonsOn: html]]
+! !
+
+!TabWidget methodsFor: 'testing'!
+
+canBeClosed
+    ^false
+! !
+
+!TabWidget class methodsFor: 'instance creation'!
+
+open
+    ^self new open
+! !
+
+Widget subclass: #SourceArea
+	instanceVariableNames: 'editor div receiver onDoIt'
+	category: 'IDE'!
+
+!SourceArea methodsFor: 'accessing'!
+
+val
+    ^editor getValue
+!
+
+val: aString
+    editor setValue: aString
 !
 
 currentLine
@@ -328,283 +438,173 @@ renderOn: html
     div onKeyDown: [:e | self handleKeyDown: e]
 ! !
 
-Widget subclass: #TabWidget
-	instanceVariableNames: 'div'
+Widget subclass: #ClassesList
+	instanceVariableNames: 'browser ul nodes'
 	category: 'IDE'!
 
-!TabWidget methodsFor: 'accessing'!
-
-label
-    self subclassResponsibility
-! !
+!ClassesList methodsFor: 'accessing'!
 
-!TabWidget methodsFor: 'actions'!
+category
+	^self browser selectedPackage
+!
 
-open
-    TabManager current addTab: self.
-    TabManager current selectTab: self
+nodes
+	nodes ifNil: [nodes := self getNodes].
+	^nodes
 !
 
-show
-	div asJQuery show
+browser
+	^browser
 !
 
-hide
-	div asJQuery hide
+browser: aBrowser
+	browser := aBrowser
 !
 
-remove
-	div asJQuery remove
+getNodes
+	| classes children others |
+	classes := self browser classes.
+	children := #().
+	others := #().
+	classes do: [:each |
+		(classes includes: each superclass)
+			ifFalse: [children add: each]
+			ifTrue: [others add: each]].
+	^children collect: [:each |
+		ClassesListNode on: each browser: self browser classes: others level: 0]
 !
 
-close
-    TabManager current closeTab: self
+resetNodes
+	nodes := nil
 ! !
 
-!TabWidget methodsFor: 'rendering'!
+!ClassesList methodsFor: 'rendering'!
 
 renderOn: html
-	div := html div
-		class: 'jtalkTool';
+	ul := html ul
+		class: 'jt_column browser classes';
 		yourself.
-	self renderTab
-!
-
-renderBoxOn: html
-!
-
-renderButtonsOn: html
-!
-
-update
-	self renderTab
+	self updateNodes
 !
 
-renderTab
-	div contents: [:html |
-	    html div
-		class: 'jt_box';
-		with: [self renderBoxOn: html].
-	    html div
-		class: 'jt_buttons';
-		with: [self renderButtonsOn: html]]
-! !
-
-!TabWidget methodsFor: 'testing'!
-
-canBeClosed
-    ^false
+updateNodes
+	ul contents: [:html |
+		self nodes do: [:each |
+			each renderOn: html]]
 ! !
 
-!TabWidget class methodsFor: 'instance creation'!
+!ClassesList class methodsFor: 'instance creation'!
 
-open
-    ^self new open
+on: aBrowser
+	^self new 
+		browser: aBrowser; 
+		yourself
 ! !
 
-Widget subclass: #TabManager
-	instanceVariableNames: 'selectedTab tabs opened ul input'
+Widget subclass: #ClassesListNode
+	instanceVariableNames: 'browser theClass level nodes'
 	category: 'IDE'!
 
-!TabManager methodsFor: 'accessing'!
-
-tabs
-    ^tabs ifNil: [tabs := Array new]
-!
+!ClassesListNode methodsFor: ''!
 
-labelFor: aWidget
-	| label maxSize |
-	maxSize := 15.
-	label := aWidget label copyFrom: 0 to: (aWidget label size min: maxSize).
-	aWidget label size > maxSize ifTrue: [
-		label := label, '...'].
-	^label
-! !
+renderOn: html
+	| li cssClass |
+	cssClass := ''.
+	li := html li 
+		onClick: [self browser selectClass: self theClass]. 
+	li asJQuery html: self label.
 
-!TabManager methodsFor: 'actions'!
+	self browser selectedClass = self theClass ifTrue:  [
+		cssClass := cssClass, ' selected'].
 
-updateBodyMargin
-    self setBodyMargin: '#jtalk' asJQuery height
-!
+	self theClass comment isEmpty ifFalse: [
+		cssClass := cssClass, ' commented'].
 
-updatePosition
-    <jQuery('#jtalk').css('top', '').css('bottom', '0px')>
-!
+	li class: cssClass.
 
-removeBodyMargin
-    self setBodyMargin: 0
-!
+	self nodes do: [:each |
+		each renderOn: html]
+! !
 
-setBodyMargin: anInteger
-    '.jtalkBody' asJQuery css: 'margin-bottom' put: anInteger asString, 'px'
-!
+!ClassesListNode methodsFor: 'accessing'!
 
-onResize: aBlock
-    <jQuery('#jtalk').resizable({
-	handles: 'n', 
-	resize: aBlock,
-	minHeight: 230
-})>
+nodes
+	^nodes
 !
 
-onWindowResize: aBlock
-    <jQuery(window).resize(aBlock)>
+theClass
+	^theClass
 !
 
-open
-    opened ifFalse: [
-	'body' asJQuery addClass: 'jtalkBody'.
-	'#jtalk' asJQuery show.
-	ul asJQuery show.
-	self updateBodyMargin.
-	selectedTab show.
-	opened := true]
+theClass: aClass
+	theClass := aClass
 !
 
-close
-    opened ifTrue: [
-	'#jtalk' asJQuery hide.
-	ul asJQuery hide.
-	selectedTab hide.
-	self removeBodyMargin.
-	'body' asJQuery removeClass: 'jtalkBody'.
-	opened := false]
+browser
+	^browser
 !
 
-newBrowserTab
-    Browser open
+browser: aBrowser
+	browser := aBrowser
 !
 
-selectTab: aWidget
-    self open.
-    selectedTab := aWidget.
-    self tabs do: [:each |
-	each hide].
-    aWidget show.
-	
-    self update
+level
+	^level
 !
 
-closeTab: aWidget
-    self removeTab: aWidget.
-    self selectTab: self tabs last.
-    aWidget remove.
-    self update
+level: anInteger
+	level := anInteger
 !
 
-search: aString
-	| searchedClass |
-	searchedClass := Smalltalk current at: aString.
-		searchedClass isClass
-			ifTrue: [Browser openOn: searchedClass]
-			ifFalse: [ReferencesBrowser search: aString]
-! !
-
-!TabManager methodsFor: 'adding/Removing'!
-
-addTab: aWidget
-    self tabs add: aWidget.
-    aWidget appendToJQuery: '#jtalk' asJQuery.
-    aWidget hide
+label
+	| str |
+	str := String new writeStream.
+	self level timesRepeat: [
+		str nextPutAll: '&nbsp;&nbsp;&nbsp;&nbsp;'].
+	str nextPutAll: self theClass name.
+	^str contents
 !
 
-removeTab: aWidget
-    self tabs remove: aWidget.
-    self update
+getNodesFrom: aCollection
+	| children others |
+	children := #().
+	others := #().
+	aCollection do: [:each |
+		(each superclass = self theClass)
+			ifTrue: [children add: each]
+			ifFalse: [others add: each]].
+	nodes:= children collect: [:each |
+		ClassesListNode on: each browser: self browser classes: others level: self level + 1]
 ! !
 
-!TabManager methodsFor: 'initialization'!
+!ClassesListNode class methodsFor: 'instance creation'!
 
-initialize
-    super initialize.
-    opened := true.
-    [:html | html div id: 'jtalk'] appendToJQuery: 'body' asJQuery.
-    'body' asJQuery 
-	addClass: 'jtalkBody'.
-    self appendToJQuery: '#jtalk' asJQuery.
-    self 
-	addTab: IDETranscript current;
-	addTab: Workspace new;
-	addTab: TestRunner new.
-    self selectTab: self tabs last.
-    self 
-	onResize: [self updateBodyMargin; updatePosition];
-	onWindowResize: [self updatePosition]
+on: aClass browser: aBrowser classes: aCollection level: anInteger
+	^self new
+		theClass: aClass;
+		browser: aBrowser;
+		level: anInteger;
+		getNodesFrom: aCollection;
+		yourself
 ! !
 
-!TabManager methodsFor: 'rendering'!
-
-renderOn: html
-	html div id: 'logo'.
-	self renderToolbarOn: html.
-	ul := html ul
-		id: 'jtalkTabs';
-		yourself.
-	self renderTabs
-!
-
-renderTabFor: aWidget on: html
-	| li |
-	li := html li.
-	selectedTab = aWidget ifTrue: [
-	li class: 'selected'].
-	li with: [
-		html span class: 'ltab'.
-		html span
-			class: 'mtab';
-			with: [
-				aWidget canBeClosed ifTrue: [
-					html span 
-						class: 'close';
-						with: 'x';
-					onClick: [self closeTab: aWidget]].
-			html span with: (self labelFor: aWidget)].
-		html span class: 'rtab'];
-	onClick: [self selectTab: aWidget]
-!
-
-renderTabs
-	ul contents: [:html |
-	    self tabs do: [:each |
-		self renderTabFor: each on: html].
-	    html li
-		class: 'newtab';
-		with: [
-			html span class: 'ltab'.
-			html span class: 'mtab'; with: ' + '.
-			html span class: 'rtab'];
-		onClick: [self newBrowserTab]]
-!
-
-renderToolbarOn: html
-	html div 
-		id: 'jt_toolbar';
-		with: [
-			input := html input 
-				class: 'implementors';
-				yourself.
-			input onKeyPress: [:event |
-				event keyCode = 13 ifTrue: [
-				self search: input asJQuery val]].
-			html div id: 'jt_close'; onClick: [self close]]
-! !
+ErrorHandler subclass: #DebugErrorHandler
+	instanceVariableNames: ''
+	category: 'IDE'!
 
-!TabManager methodsFor: 'updating'!
+!DebugErrorHandler methodsFor: 'error handling'!
 
-update
-	self renderTabs
+handleError: anError
+	[Debugger new
+		error: anError;
+		open] on: Error do: [:error |
+			ErrorHandler new handleError: error]
 ! !
 
-TabManager class instanceVariableNames: 'current'!
-
-!TabManager class methodsFor: 'instance creation'!
-
-current
-    ^current ifNil: [current := super new]
-!
+!DebugErrorHandler class methodsFor: 'initialization'!
 
-new
-    self shouldNotImplement
+initialize
+	self register
 ! !
 
 TabWidget subclass: #Workspace
@@ -2195,6 +2195,7 @@ cr
 !
 
 show: anObject
+    textarea ifNil: [self open].
     textarea asJQuery val: textarea asJQuery val, anObject asString.
 !
 

+ 5 - 1
st/Kernel-Collections.st

@@ -385,7 +385,11 @@ ifNotEmpty: aBlock
 !
 
 ifEmpty: aBlock
-	self isEmpty ifTrue: aBlock.
+	"Evaluate the given block with the receiver as argument, answering its value if the receiver is empty, otherwise answer the receiver. Note that the fact that this method returns its argument in case the receiver is not empty allows one to write expressions like the following ones: self classifyMethodAs: 
+		(myProtocol ifEmpty: ['As yet unclassified'])"
+	^ self isEmpty 
+		ifTrue: [ aBlock value ]
+		ifFalse: [ self ]
 ! !
 
 !Collection class methodsFor: 'accessing'!

+ 590 - 586
st/Kernel-Tests.st

@@ -1,438 +1,387 @@
 Smalltalk current createPackage: 'Kernel-Tests' properties: #{}!
-TestCase subclass: #SetTest
+TestCase subclass: #ArrayTest
 	instanceVariableNames: ''
 	category: 'Kernel-Tests'!
 
-!SetTest methodsFor: 'tests'!
+!ArrayTest methodsFor: 'testing'!
 
-testUnicity
-	| set |
-	set := Set new.
-	set add: 21.
-	set add: 'hello'.
+testFirstN
+	self assert: {1. 2. 3} equals: ({1. 2. 3. 4. 5} first: 3).
+!
 
-	set add: 21.
-	self assert: set size = 2.
-	
-	set add: 'hello'.
-	self assert: set size = 2.
+testIfEmpty
+	self assert: 'zork' equals: ( '' ifEmpty: ['zork'] )
+! !
 
-	self assert: set asArray equals: #(21 'hello')
+TestCase subclass: #StringTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
+
+!StringTest methodsFor: 'tests'!
+
+testJoin
+	self assert: 'hello,world' equals: (',' join: #('hello' 'world'))
 !
 
-testAt
-	self should: [Set new at: 1 put: 2] raise: Error
+testStreamContents
+	self 
+		assert: 'hello world' 
+		equals: (String streamContents: [:aStream| aStream 
+                                                 					nextPutAll: 'hello'; space; 
+                                                 					nextPutAll: 'world'])
 !
 
-testAddRemove
-	| set |
-	set := Set new.
-	
-	self assert: set isEmpty.
+testIncludesSubString
+	self assert: ('amber' includesSubString: 'ber').
+	self deny: ('amber' includesSubString: 'zork').
+!
 
-	set add: 3.
-	self assert: (set includes: 3).
+testEquality
+	self assert: 'hello' = 'hello'.
+	self deny: 'hello' = 'world'.
 
-	set add: 5.
-	self assert: (set includes: 5).
+	self assert: 'hello'  = 'hello' yourself.
+	self assert: 'hello' yourself = 'hello'.
 
-	set remove: 3.
-	self deny: (set includes: 3)
+	"test JS falsy value"
+	self deny: '' = 0
 !
 
-testSize
-	self assert: Set new size equals: 0.
-	self assert: (Set withAll: #(1 2 3 4)) size equals: 4.
-	self assert: (Set withAll: #(1 1 1 1)) size equals: 1
-! !
-
-TestCase subclass: #ClassBuilderTest
-	instanceVariableNames: 'builder theClass'
-	category: 'Kernel-Tests'!
+testCopyWithoutAll
+	self 
+		assert: 'hello world' 
+		equals: ('*hello* *world*' copyWithoutAll: '*')
+!
 
-!ClassBuilderTest methodsFor: 'running'!
+testAt
+	self assert: ('hello' at: 1) = 'h'.
+	self assert: ('hello' at: 5) = 'o'.
+	self assert: ('hello' at: 6 ifAbsent: [nil]) = nil
+!
 
-setUp
-	builder := ClassBuilder new
+testAtPut
+	"String instances are read-only"
+	self should: ['hello' at: 1 put: 'a'] raise: Error
 !
 
-tearDown
-	theClass ifNotNil: [Smalltalk current removeClass: theClass. theClass := nil]
+testSize
+	self assert: 'smalltalk' size equals: 9.
+	self assert: '' size equals: 0
 !
 
-testClassCopy
-	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
-	self assert: theClass superclass == ObjectMock superclass.
-	self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.
-	self assert: theClass name equals: 'ObjectMock2'.
-	self assert: theClass package == ObjectMock package.
-	self assert: theClass methodDictionary keys equals: ObjectMock methodDictionary keys
+testAddRemove
+	self should: ['hello' add: 'a'] raise: Error.
+	self should: ['hello' remove: 'h'] raise: Error
 !
 
-testInstanceVariableNames
-	self assert: (builder instanceVariableNamesFor: '  hello   world   ') equals: #('hello' 'world')
+testAsArray
+	self assert: 'hello' asArray = #('h' 'e' 'l' 'l' 'o').
 ! !
 
-TestCase subclass: #RandomTest
+TestCase subclass: #DictionaryTest
 	instanceVariableNames: ''
 	category: 'Kernel-Tests'!
 
-!RandomTest methodsFor: 'tests'!
+!DictionaryTest methodsFor: 'tests'!
 
-textNext
+testPrintString
+	self
+		assert: 'a Dictionary(''firstname'' -> ''James'' , ''lastname'' -> ''Bond'')' 
+		equals: (Dictionary new 
+                         	at:'firstname' put: 'James';
+                        	at:'lastname' put: 'Bond';
+                        	printString)
+!
 
-	10000 timesRepeat: [
-			| current next | 
-			next := Random new next.
-			self assert: (next >= 0).
-			self assert: (next < 1).
-			self deny: current = next.
-			next = current]
-! !
+testEquality
+	| d1 d2 |
 
-TestCase subclass: #PointTest
-	instanceVariableNames: ''
-	category: 'Kernel-Tests'!
+	self assert: Dictionary new = Dictionary new.
+		
+	d1 := Dictionary new at: 1 put: 2; yourself.
+	d2 := Dictionary new at: 1 put: 2; yourself.
+	self assert: d1 = d2.
 
-!PointTest methodsFor: 'tests'!
+	d2 := Dictionary new at: 1 put: 3; yourself.
+	self deny: d1 = d2.
 
-testAccessing
-	self assert: (Point x: 3 y: 4) x equals: 3.
-	self assert: (Point x: 3 y: 4) y equals: 4.
-	self assert: (Point new x: 3) x equals: 3.
-	self assert: (Point new y: 4) y equals: 4
-!
+	d2 := Dictionary new at: 2 put: 2; yourself.
+	self deny: d1 = d2.
 
-testAt
-	self assert: 3@4 equals: (Point x: 3 y: 4)
+	d2 := Dictionary new at: 1 put: 2; at: 3 put: 4; yourself.
+	self deny: d1 = d2.
 !
 
-testEgality
-	self assert: 3@4 = (3@4).
-	self deny: 3@5 = (3@6)
+testDynamicDictionaries
+	self assert: #{'hello' -> 1} asDictionary = (Dictionary with: 'hello' -> 1)
 !
 
-testArithmetic
-	self assert: 3@4 * (3@4 ) equals: (Point x: 9 y: 16).
-	self assert: 3@4 + (3@4 ) equals: (Point x: 6 y: 8).
-	self assert: 3@4 - (3@4 ) equals: (Point x: 0 y: 0).
-	self assert: 6@8 / (3@4 ) equals: (Point x: 2 y: 2)
-!
+testAccessing
+	| d |
 
-testTranslateBy
-	self assert: 3@4 equals: (3@3 translateBy: 0@1).
-	self assert: 3@2 equals: (3@3 translateBy: 0@1 negated).
-	self assert: 5@6 equals: (3@3 translateBy: 2@3).
-	self assert: 0@3 equals: (3@3 translateBy: 3 negated @0).
-! !
+	d := Dictionary new.
 
-TestCase subclass: #UndefinedTest
-	instanceVariableNames: ''
-	category: 'Kernel-Tests'!
+	d at: 'hello' put: 'world'.
+	self assert: (d at: 'hello') = 'world'.
+	self assert: (d at: 'hello' ifAbsent: [nil]) = 'world'.
+	self deny: (d at: 'foo' ifAbsent: [nil]) = 'world'.
 
-!UndefinedTest methodsFor: 'tests'!
+	d at: 1 put: 2.
+	self assert: (d at: 1) = 2.
 
-testIsNil
-	self assert: nil isNil.
-	self deny: nil notNil.
+	d at: 1@3 put: 3.
+	self assert: (d at: 1@3) = 3
 !
 
-testIfNil
-	self assert: (nil ifNil: [true]) equals: true.
-	self deny: (nil ifNotNil: [true]) = true.
-	self assert: (nil ifNil: [true] ifNotNil: [false]) equals: true.
-	self deny: (nil ifNotNil: [true] ifNil: [false]) = true
-!
+testSize
+	| d |
 
-testCopying
-	self assert: nil copy equals: nil
-!
+	d := Dictionary new.
+	self assert: d size = 0.
 
-testDeepCopy
-	self assert: nil deepCopy = nil
-! !
+	d at: 1 put: 2.
+	self assert: d size = 1.
 
-Object subclass: #ObjectMock
-	instanceVariableNames: 'foo bar'
-	category: 'Kernel-Tests'!
+	d at: 2 put: 3.
+	self assert: d size = 2.
+!
 
-!ObjectMock methodsFor: 'not yet classified'!
+testValues
+	| d |
 
-foo
-	^foo
+	d := Dictionary new.
+	d at: 1 put: 2.
+	d at: 2 put: 3.
+	d at: 3 put: 4.
+
+	self assert: d values = #(2 3 4)
 !
 
-foo: anObject
-	foo := anObject
+testKeys
+	| d |
+
+	d := Dictionary new.
+	d at: 1 put: 2.
+	d at: 2 put: 3.
+	d at: 3 put: 4.
+
+	self assert: d keys = #(1 2 3)
 ! !
 
-TestCase subclass: #SymbolTest
+TestCase subclass: #BooleanTest
 	instanceVariableNames: ''
 	category: 'Kernel-Tests'!
 
-!SymbolTest methodsFor: 'tests'!
-
-testEquality
-	self assert: #hello = #hello.
-	self deny: #hello = #world.
-
-	self assert: #hello  = #hello yourself.
-	self assert: #hello yourself = #hello.
+!BooleanTest methodsFor: 'tests'!
 
-	self deny: #hello  = 'hello'.
-	self deny: 'hello' = #hello.
+testLogic
+ 
+	"Trivial logic table"
+	self assert: (true & true); deny: (true & false); deny: (false & true); deny: (false & false).
+	self assert: (true | true); assert: (true | false); assert: (false | true); deny: (false | false).
+        "Checking that expressions work fine too"
+	self assert: (true & (1 > 0)); deny: ((1 > 0) & false); deny: ((1 > 0) & (1 > 2)).
+        self assert: (false | (1 > 0)); assert: ((1 > 0) | false); assert: ((1 > 0) | (1 > 2))
 !
 
-testAt
-	self assert: (#hello at: 1) = 'h'.
-	self assert: (#hello at: 5) = 'o'.
-	self assert: (#hello at: 6 ifAbsent: [nil]) = nil
-!
+testEquality
+	"We're on top of JS...just be sure to check the basics!!"
 
-testAtPut
-	"Symbol instances are read-only"
-	self should: ['hello' at: 1 put: 'a'] raise: Error
-!
-
-testIdentity
-	self assert: #hello == #hello.
-	self deny: #hello == #world.
-
-	self assert: #hello  = #hello yourself.
-	self assert: #hello yourself = #hello asString asSymbol
-!
-
-testComparing
-	self assert: #ab > #aa.
-	self deny: #ab > #ba.
-
-	self assert: #ab < #ba.
-	self deny: #bb < #ba.
+	self deny: 0 = false. 
+	self deny: false = 0.
+	self deny: '' = false.
+	self deny: false = ''.
 
-	self assert: #ab >= #aa.
-	self deny: #ab >= #ba.
+	self assert: true = true.
+	self deny: false = true.
+	self deny: true = false.
+	self assert: false = false.
 
-	self assert: #ab <= #ba.
-	self deny: #bb <= #ba
+	"JS may do some type coercing after sending a message"
+	self assert: true yourself = true.
+	self assert: true yourself = true yourself
 !
 
-testSize
-	self assert: #a size equals: 1.
-	self assert: #aaaaa size equals: 5
+testLogicKeywords
+ 
+	"Trivial logic table"
+	self 
+		assert: (true and: [ true]); 
+		deny: (true and: [ false ]); 
+		deny: (false and: [ true ]); 
+		deny: (false and: [ false ]).
+	self 
+		assert: (true or: [ true ]); 
+		assert: (true or: [ false ]); 
+		assert: (false or: [ true ]); 
+		deny: (false or: [ false ]).
+        
+	"Checking that expressions work fine too"
+	self 
+		assert: (true and: [ 1 > 0 ]); 
+		deny: ((1 > 0) and: [ false ]); 
+		deny: ((1 > 0) and: [ 1 > 2 ]).
+        self 
+		assert: (false or: [ 1 > 0 ]); 
+		assert: ((1 > 0) or: [ false ]); 
+		assert: ((1 > 0) or: [ 1 > 2 ])
 !
 
-testAsString
-	self assert: #hello asString equals: 'hello'
-!
+testIfTrueIfFalse
+ 
+	self assert: (true ifTrue: ['alternative block']) = 'alternative block'.
+	self assert: (true ifFalse: ['alternative block']) = nil.
 
-testAsSymbol
-	self assert: #hello == #hello asSymbol
-!
+	self assert: (false ifTrue: ['alternative block']) = nil.
+	self assert: (false ifFalse: ['alternative block']) = 'alternative block'.
 
-testCopying
-	self assert: #hello copy == #hello.
-	self assert: #hello deepCopy == #hello
-!
+	self assert: (false ifTrue: ['alternative block'] ifFalse: ['alternative block2']) = 'alternative block2'.
+	self assert: (false ifFalse: ['alternative block'] ifTrue: ['alternative block2']) = 'alternative block'.
 
-testIsSymbolIsString
-	self assert: #hello isSymbol.
-	self deny: 'hello' isSymbol.
-	self deny: #hello isString.
-	self assert: 'hello' isString
+	self assert: (true ifTrue: ['alternative block'] ifFalse: ['alternative block2']) = 'alternative block'.
+	self assert: (true ifFalse: ['alternative block'] ifTrue: ['alternative block2']) = 'alternative block2'.
 ! !
 
-TestCase subclass: #ObjectTest
+TestCase subclass: #NumberTest
 	instanceVariableNames: ''
 	category: 'Kernel-Tests'!
 
-!ObjectTest methodsFor: 'tests'!
+!NumberTest methodsFor: 'tests'!
 
-testEquality
-	| o |
-	o := Object new.
-	self deny: o = Object new.
-	self assert: o = o.
-	self assert: o yourself = o.
-	self assert: o = o yourself
+testPrintShowingDecimalPlaces
+	self assert: '23.00' equals: (23 printShowingDecimalPlaces: 2).
+	self assert: '23.57' equals: (23.5698 printShowingDecimalPlaces: 2).
+	self assert: '-234.56700' equals:( 234.567 negated printShowingDecimalPlaces: 5).
+	self assert: '23' equals: (23.4567 printShowingDecimalPlaces: 0).
+	self assert: '24' equals: (23.5567 printShowingDecimalPlaces: 0).
+	self assert: '-23' equals: (23.4567 negated printShowingDecimalPlaces: 0).
+	self assert: '-24' equals: (23.5567 negated printShowingDecimalPlaces: 0).
+	self assert: '100000000.0' equals: (100000000 printShowingDecimalPlaces: 1).
+	self assert: '0.98000' equals: (0.98 printShowingDecimalPlaces: 5).
+	self assert: '-0.98' equals: (0.98 negated printShowingDecimalPlaces: 2).
+	self assert: '2.57' equals: (2.567 printShowingDecimalPlaces: 2).
+	self assert: '-2.57' equals: (-2.567 printShowingDecimalPlaces: 2).
+	self assert: '0.00' equals: (0 printShowingDecimalPlaces: 2).
 !
 
-testIdentity
-	| o |
-	o := Object new.
-	self deny: o == Object new.
-	self assert: o == o
-!
+testEquality
+	self assert: 1 = 1.
+	self assert: 0 = 0.
+	self deny: 1 = 0.
 
-testHalt
-	self should: [Object new halt] raise: Error
+	self assert: 1 yourself = 1.
+	self assert: 1 = 1 yourself.
+	self assert: 1 yourself = 1 yourself.
+	
+	self deny: 0 = false.
+	self deny: false = 0.
+	self deny: '' = 0.
+	self deny: 0 = ''
 !
 
-testBasicAccess
-	| o |
-	o := Object new.
-	o basicAt: 'a' put: 1.
-	self assert: (o basicAt: 'a') equals: 1.
-	self assert: (o basicAt: 'b') equals: nil
-!
+testArithmetic
+	
+	"We rely on JS here, so we won't test complex behavior, just check if 
+	message sends are corrects"
 
-testNilUndefined
-	"nil in Smalltalk is the undefined object in JS"
+	self assert: 1.5 + 1 = 2.5.
+	self assert: 2 - 1 = 1.
+	self assert: -2 - 1 = -3.
+	self assert: 12 / 2 = 6.
+	self assert: 3 * 4 = 12.
 
-	self assert: nil = undefined
+	"Simple parenthesis and execution order"
+
+	self assert: 1 + 2 * 3 = 9.
+	self assert: 1 + (2 * 3) = 7
 !
 
-testidentityHash
-	| o1 o2 |
+testRounded
 	
-	o1 := Object new.
-	o2 := Object new.
-
-	self assert: o1 identityHash == o1 identityHash.
-	self deny: o1 identityHash == o2 identityHash
+	self assert: 3 rounded = 3.
+	self assert: 3.212 rounded = 3.
+	self assert: 3.51 rounded = 4
 !
 
-testBasicPerform
-	| o |
-	o := Object new.
-	o basicAt: 'func' put: ['hello'].	
-	o basicAt: 'func2' put: [:a | a + 1].
-
-	self assert: (o basicPerform: 'func')	 equals: 'hello'.
-	self assert: (o basicPerform: 'func2' withArguments: #(3)) equals: 4
+testNegated
+	self assert: 3 negated = -3.
+	self assert: -3 negated = 3
 !
 
-testIfNil
-	self deny: Object new isNil.
-	self deny: (Object new ifNil: [true]) = true.
-	self assert: (Object new ifNotNil: [true]) = true.
-
-	self assert: (Object new ifNil: [false] ifNotNil: [true]) = true.
-	self assert: (Object new ifNotNil: [true] ifNil: [false]) = true
-!
+testComparison
 
-testInstVars
-	| o |
-	o := ObjectMock new.
-	self assert: (o instVarAt: #foo) equals: nil.
+	self assert: 3 > 2.
+	self assert: 2 < 3.
+	
+	self deny: 3 < 2.
+	self deny: 2 > 3.
 
-	o instVarAt: #foo put: 1.
-	self assert: (o instVarAt: #foo) equals: 1.
-	self assert: (o instVarAt: 'foo') equals: 1
+	self assert: 3 >= 3.
+	self assert: 3.1 >= 3.
+	self assert: 3 <= 3.
+	self assert: 3 <= 3.1
 !
 
-testYourself
-	| o |
-	o := ObjectMock new.
-	self assert: o yourself == o
+testTruncated
+	
+	self assert: 3 truncated = 3.
+	self assert: 3.212 truncated = 3.
+	self assert: 3.51 truncated = 3
 !
 
-testDNU
-	self should: [Object new foo] raise: MessageNotUnderstood
-! !
-
-TestCase subclass: #BlockClosureTest
-	instanceVariableNames: ''
-	category: 'Kernel-Tests'!
-
-!BlockClosureTest methodsFor: 'tests'!
-
-testValue
-	self assert: ([1+1] value) equals: 2.
-	self assert: ([:x | x +1] value: 2) equals: 3.
-	self assert: ([:x :y | x*y] value: 2 value: 4) equals: 8. 
-
-	"Arguments are optional in Amber. This isn't ANSI compliant."
-
-	self assert: ([:a :b :c | 1] value) equals: 1
+testCopying
+	self assert: 1 copy == 1.
+	self assert: 1 deepCopy == 1
 !
 
-testOnDo
-	self assert: ([Error new signal] on: Error do: [:ex | true])
+testMinMax
+	
+	self assert: (2 max: 5) equals: 5.
+	self assert: (2 min: 5) equals: 2
 !
 
-testEnsure
-	self assert: ([Error new] ensure: [true])
-!
+testIdentity
+	self assert: 1 == 1.
+	self assert: 0 == 0.
+	self deny: 1 == 0.
 
-testNumArgs
-	self assert: [] numArgs equals: 0.
-	self assert: [:a :b | ] numArgs equals: 2
+	self assert: 1 yourself == 1.
+	self assert: 1 == 1 yourself.
+	self assert: 1 yourself == 1 yourself.
+	
+	self deny: 1 == 2
 !
 
-testValueWithPossibleArguments
-	self assert: ([1] valueWithPossibleArguments: #(3 4)) equals: 1.
-	self assert: ([:a | a + 4] valueWithPossibleArguments: #(3 4)) equals: 7.
-	self assert: ([:a :b | a + b] valueWithPossibleArguments: #(3 4 5)) equals: 7.
+testSqrt
+	
+	self assert: 4 sqrt = 2.
+	self assert: 16 sqrt = 4
 !
 
-testWhileTrue
-	| i |
-	i := 0.
-	[i < 5] whileTrue: [i := i + 1].
-	self assert: i equals: 5.
-
-	i := 0.
-	[i := i + 1. i < 5] whileTrue.
-	self assert: i equals: 5
+testSquared
+	
+	self assert: 4 squared = 16
 !
 
-testWhileFalse
+testTimesRepeat
 	| i |
-	i := 0.
-	[i > 5] whileFalse: [i := i + 1].
-	self assert: i equals: 6.
 
 	i := 0.
-	[i := i + 1. i > 5] whileFalse.
-	self assert: i equals: 6
-!
-
-testCompiledSource
-	self assert: ([1+1] compiledSource includesSubString: 'function')
-! !
-
-TestCase subclass: #PackageTest
-	instanceVariableNames: 'zorkPackage grulPackage backUpCommitPathJs backUpCommitPathSt'
-	category: 'Kernel-Tests'!
-
-!PackageTest methodsFor: 'running'!
-
-setUp
-	backUpCommitPathJs := Package defaultCommitPathJs.
-	backUpCommitPathSt := Package defaultCommitPathSt.
-
-	Package resetCommitPaths.
-
-	zorkPackage := Package new name: 'Zork'.
-	grulPackage := Package new 
-					name: 'Grul';
-					commitPathJs: 'server/grul/js';
-					commitPathSt: 'grul/st';
-					yourself
-!
-
-tearDown
-	 Package 
-		defaultCommitPathJs: backUpCommitPathJs;
-		defaultCommitPathSt: backUpCommitPathSt
-! !
-
-!PackageTest methodsFor: 'tests'!
+	0 timesRepeat: [i := i + 1].
+	self assert: i equals: 0.
 
-testGrulCommitPathStShouldBeGrulSt
-	self assert: 'grul/st' equals: grulPackage commitPathSt
+	5 timesRepeat: [i := i + 1].
+	self assert: i equals: 5
 !
 
-testZorkCommitPathStShouldBeSt
-	self assert: 'st' equals: zorkPackage commitPathSt
+testTo
+	self assert: (1 to: 5) equals: #(1 2 3 4 5)
 !
 
-testZorkCommitPathJsShouldBeJs
-	self assert: 'js' equals: zorkPackage commitPathJs
-!
+testToBy
+	self assert: (0 to: 6 by: 2) equals: #(0 2 4 6).
 
-testGrulCommitPathJsShouldBeServerGrulJs
-	self assert: 'server/grul/js' equals: grulPackage commitPathJs
+	self should: [1 to: 4 by: 0] raise: Error
 ! !
 
 TestCase subclass: #JSObjectProxyTest
@@ -492,385 +441,440 @@ testPrinting
 	self assert: self jsObject printString = '[object Object]'
 ! !
 
-TestCase subclass: #NumberTest
-	instanceVariableNames: ''
+TestCase subclass: #PackageTest
+	instanceVariableNames: 'zorkPackage grulPackage backUpCommitPathJs backUpCommitPathSt'
 	category: 'Kernel-Tests'!
 
-!NumberTest methodsFor: 'tests'!
+!PackageTest methodsFor: 'running'!
 
-testPrintShowingDecimalPlaces
-	self assert: '23.00' equals: (23 printShowingDecimalPlaces: 2).
-	self assert: '23.57' equals: (23.5698 printShowingDecimalPlaces: 2).
-	self assert: '-234.56700' equals:( 234.567 negated printShowingDecimalPlaces: 5).
-	self assert: '23' equals: (23.4567 printShowingDecimalPlaces: 0).
-	self assert: '24' equals: (23.5567 printShowingDecimalPlaces: 0).
-	self assert: '-23' equals: (23.4567 negated printShowingDecimalPlaces: 0).
-	self assert: '-24' equals: (23.5567 negated printShowingDecimalPlaces: 0).
-	self assert: '100000000.0' equals: (100000000 printShowingDecimalPlaces: 1).
-	self assert: '0.98000' equals: (0.98 printShowingDecimalPlaces: 5).
-	self assert: '-0.98' equals: (0.98 negated printShowingDecimalPlaces: 2).
-	self assert: '2.57' equals: (2.567 printShowingDecimalPlaces: 2).
-	self assert: '-2.57' equals: (-2.567 printShowingDecimalPlaces: 2).
-	self assert: '0.00' equals: (0 printShowingDecimalPlaces: 2).
+setUp
+	backUpCommitPathJs := Package defaultCommitPathJs.
+	backUpCommitPathSt := Package defaultCommitPathSt.
+
+	Package resetCommitPaths.
+
+	zorkPackage := Package new name: 'Zork'.
+	grulPackage := Package new 
+					name: 'Grul';
+					commitPathJs: 'server/grul/js';
+					commitPathSt: 'grul/st';
+					yourself
 !
 
-testEquality
-	self assert: 1 = 1.
-	self assert: 0 = 0.
-	self deny: 1 = 0.
+tearDown
+	 Package 
+		defaultCommitPathJs: backUpCommitPathJs;
+		defaultCommitPathSt: backUpCommitPathSt
+! !
 
-	self assert: 1 yourself = 1.
-	self assert: 1 = 1 yourself.
-	self assert: 1 yourself = 1 yourself.
-	
-	self deny: 0 = false.
-	self deny: false = 0.
-	self deny: '' = 0.
-	self deny: 0 = ''
+!PackageTest methodsFor: 'tests'!
+
+testGrulCommitPathStShouldBeGrulSt
+	self assert: 'grul/st' equals: grulPackage commitPathSt
+!
+
+testZorkCommitPathStShouldBeSt
+	self assert: 'st' equals: zorkPackage commitPathSt
+!
+
+testZorkCommitPathJsShouldBeJs
+	self assert: 'js' equals: zorkPackage commitPathJs
+!
+
+testGrulCommitPathJsShouldBeServerGrulJs
+	self assert: 'server/grul/js' equals: grulPackage commitPathJs
+! !
+
+TestCase subclass: #BlockClosureTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
+
+!BlockClosureTest methodsFor: 'tests'!
+
+testValue
+	self assert: ([1+1] value) equals: 2.
+	self assert: ([:x | x +1] value: 2) equals: 3.
+	self assert: ([:x :y | x*y] value: 2 value: 4) equals: 8. 
+
+	"Arguments are optional in Amber. This isn't ANSI compliant."
+
+	self assert: ([:a :b :c | 1] value) equals: 1
 !
 
-testArithmetic
-	
-	"We rely on JS here, so we won't test complex behavior, just check if 
-	message sends are corrects"
+testOnDo
+	self assert: ([Error new signal] on: Error do: [:ex | true])
+!
 
-	self assert: 1.5 + 1 = 2.5.
-	self assert: 2 - 1 = 1.
-	self assert: -2 - 1 = -3.
-	self assert: 12 / 2 = 6.
-	self assert: 3 * 4 = 12.
+testEnsure
+	self assert: ([Error new] ensure: [true])
+!
 
-	"Simple parenthesis and execution order"
+testNumArgs
+	self assert: [] numArgs equals: 0.
+	self assert: [:a :b | ] numArgs equals: 2
+!
 
-	self assert: 1 + 2 * 3 = 9.
-	self assert: 1 + (2 * 3) = 7
+testValueWithPossibleArguments
+	self assert: ([1] valueWithPossibleArguments: #(3 4)) equals: 1.
+	self assert: ([:a | a + 4] valueWithPossibleArguments: #(3 4)) equals: 7.
+	self assert: ([:a :b | a + b] valueWithPossibleArguments: #(3 4 5)) equals: 7.
 !
 
-testRounded
-	
-	self assert: 3 rounded = 3.
-	self assert: 3.212 rounded = 3.
-	self assert: 3.51 rounded = 4
+testWhileTrue
+	| i |
+	i := 0.
+	[i < 5] whileTrue: [i := i + 1].
+	self assert: i equals: 5.
+
+	i := 0.
+	[i := i + 1. i < 5] whileTrue.
+	self assert: i equals: 5
 !
 
-testNegated
-	self assert: 3 negated = -3.
-	self assert: -3 negated = 3
+testWhileFalse
+	| i |
+	i := 0.
+	[i > 5] whileFalse: [i := i + 1].
+	self assert: i equals: 6.
+
+	i := 0.
+	[i := i + 1. i > 5] whileFalse.
+	self assert: i equals: 6
 !
 
-testComparison
+testCompiledSource
+	self assert: ([1+1] compiledSource includesSubString: 'function')
+! !
 
-	self assert: 3 > 2.
-	self assert: 2 < 3.
-	
-	self deny: 3 < 2.
-	self deny: 2 > 3.
+TestCase subclass: #ObjectTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
 
-	self assert: 3 >= 3.
-	self assert: 3.1 >= 3.
-	self assert: 3 <= 3.
-	self assert: 3 <= 3.1
+!ObjectTest methodsFor: 'tests'!
+
+testEquality
+	| o |
+	o := Object new.
+	self deny: o = Object new.
+	self assert: o = o.
+	self assert: o yourself = o.
+	self assert: o = o yourself
 !
 
-testTruncated
-	
-	self assert: 3 truncated = 3.
-	self assert: 3.212 truncated = 3.
-	self assert: 3.51 truncated = 3
+testIdentity
+	| o |
+	o := Object new.
+	self deny: o == Object new.
+	self assert: o == o
 !
 
-testCopying
-	self assert: 1 copy == 1.
-	self assert: 1 deepCopy == 1
+testHalt
+	self should: [Object new halt] raise: Error
 !
 
-testMinMax
-	
-	self assert: (2 max: 5) equals: 5.
-	self assert: (2 min: 5) equals: 2
+testBasicAccess
+	| o |
+	o := Object new.
+	o basicAt: 'a' put: 1.
+	self assert: (o basicAt: 'a') equals: 1.
+	self assert: (o basicAt: 'b') equals: nil
 !
 
-testIdentity
-	self assert: 1 == 1.
-	self assert: 0 == 0.
-	self deny: 1 == 0.
+testNilUndefined
+	"nil in Smalltalk is the undefined object in JS"
 
-	self assert: 1 yourself == 1.
-	self assert: 1 == 1 yourself.
-	self assert: 1 yourself == 1 yourself.
-	
-	self deny: 1 == 2
+	self assert: nil = undefined
 !
 
-testSqrt
+testidentityHash
+	| o1 o2 |
 	
-	self assert: 4 sqrt = 2.
-	self assert: 16 sqrt = 4
-!
+	o1 := Object new.
+	o2 := Object new.
 
-testSquared
-	
-	self assert: 4 squared = 16
+	self assert: o1 identityHash == o1 identityHash.
+	self deny: o1 identityHash == o2 identityHash
 !
 
-testTimesRepeat
-	| i |
+testBasicPerform
+	| o |
+	o := Object new.
+	o basicAt: 'func' put: ['hello'].	
+	o basicAt: 'func2' put: [:a | a + 1].
 
-	i := 0.
-	0 timesRepeat: [i := i + 1].
-	self assert: i equals: 0.
+	self assert: (o basicPerform: 'func')	 equals: 'hello'.
+	self assert: (o basicPerform: 'func2' withArguments: #(3)) equals: 4
+!
 
-	5 timesRepeat: [i := i + 1].
-	self assert: i equals: 5
+testIfNil
+	self deny: Object new isNil.
+	self deny: (Object new ifNil: [true]) = true.
+	self assert: (Object new ifNotNil: [true]) = true.
+
+	self assert: (Object new ifNil: [false] ifNotNil: [true]) = true.
+	self assert: (Object new ifNotNil: [true] ifNil: [false]) = true
 !
 
-testTo
-	self assert: (1 to: 5) equals: #(1 2 3 4 5)
+testInstVars
+	| o |
+	o := ObjectMock new.
+	self assert: (o instVarAt: #foo) equals: nil.
+
+	o instVarAt: #foo put: 1.
+	self assert: (o instVarAt: #foo) equals: 1.
+	self assert: (o instVarAt: 'foo') equals: 1
 !
 
-testToBy
-	self assert: (0 to: 6 by: 2) equals: #(0 2 4 6).
+testYourself
+	| o |
+	o := ObjectMock new.
+	self assert: o yourself == o
+!
 
-	self should: [1 to: 4 by: 0] raise: Error
+testDNU
+	self should: [Object new foo] raise: MessageNotUnderstood
 ! !
 
-TestCase subclass: #BooleanTest
+TestCase subclass: #SymbolTest
 	instanceVariableNames: ''
 	category: 'Kernel-Tests'!
 
-!BooleanTest methodsFor: 'tests'!
+!SymbolTest methodsFor: 'tests'!
 
-testLogic
- 
-	"Trivial logic table"
-	self assert: (true & true); deny: (true & false); deny: (false & true); deny: (false & false).
-	self assert: (true | true); assert: (true | false); assert: (false | true); deny: (false | false).
-        "Checking that expressions work fine too"
-	self assert: (true & (1 > 0)); deny: ((1 > 0) & false); deny: ((1 > 0) & (1 > 2)).
-        self assert: (false | (1 > 0)); assert: ((1 > 0) | false); assert: ((1 > 0) | (1 > 2))
+testEquality
+	self assert: #hello = #hello.
+	self deny: #hello = #world.
+
+	self assert: #hello  = #hello yourself.
+	self assert: #hello yourself = #hello.
+
+	self deny: #hello  = 'hello'.
+	self deny: 'hello' = #hello.
 !
 
-testEquality
-	"We're on top of JS...just be sure to check the basics!!"
+testAt
+	self assert: (#hello at: 1) = 'h'.
+	self assert: (#hello at: 5) = 'o'.
+	self assert: (#hello at: 6 ifAbsent: [nil]) = nil
+!
 
-	self deny: 0 = false. 
-	self deny: false = 0.
-	self deny: '' = false.
-	self deny: false = ''.
+testAtPut
+	"Symbol instances are read-only"
+	self should: ['hello' at: 1 put: 'a'] raise: Error
+!
 
-	self assert: true = true.
-	self deny: false = true.
-	self deny: true = false.
-	self assert: false = false.
+testIdentity
+	self assert: #hello == #hello.
+	self deny: #hello == #world.
 
-	"JS may do some type coercing after sending a message"
-	self assert: true yourself = true.
-	self assert: true yourself = true yourself
+	self assert: #hello  = #hello yourself.
+	self assert: #hello yourself = #hello asString asSymbol
 !
 
-testLogicKeywords
- 
-	"Trivial logic table"
-	self 
-		assert: (true and: [ true]); 
-		deny: (true and: [ false ]); 
-		deny: (false and: [ true ]); 
-		deny: (false and: [ false ]).
-	self 
-		assert: (true or: [ true ]); 
-		assert: (true or: [ false ]); 
-		assert: (false or: [ true ]); 
-		deny: (false or: [ false ]).
-        
-	"Checking that expressions work fine too"
-	self 
-		assert: (true and: [ 1 > 0 ]); 
-		deny: ((1 > 0) and: [ false ]); 
-		deny: ((1 > 0) and: [ 1 > 2 ]).
-        self 
-		assert: (false or: [ 1 > 0 ]); 
-		assert: ((1 > 0) or: [ false ]); 
-		assert: ((1 > 0) or: [ 1 > 2 ])
+testComparing
+	self assert: #ab > #aa.
+	self deny: #ab > #ba.
+
+	self assert: #ab < #ba.
+	self deny: #bb < #ba.
+
+	self assert: #ab >= #aa.
+	self deny: #ab >= #ba.
+
+	self assert: #ab <= #ba.
+	self deny: #bb <= #ba
 !
 
-testIfTrueIfFalse
- 
-	self assert: (true ifTrue: ['alternative block']) = 'alternative block'.
-	self assert: (true ifFalse: ['alternative block']) = nil.
+testSize
+	self assert: #a size equals: 1.
+	self assert: #aaaaa size equals: 5
+!
 
-	self assert: (false ifTrue: ['alternative block']) = nil.
-	self assert: (false ifFalse: ['alternative block']) = 'alternative block'.
+testAsString
+	self assert: #hello asString equals: 'hello'
+!
 
-	self assert: (false ifTrue: ['alternative block'] ifFalse: ['alternative block2']) = 'alternative block2'.
-	self assert: (false ifFalse: ['alternative block'] ifTrue: ['alternative block2']) = 'alternative block'.
+testAsSymbol
+	self assert: #hello == #hello asSymbol
+!
 
-	self assert: (true ifTrue: ['alternative block'] ifFalse: ['alternative block2']) = 'alternative block'.
-	self assert: (true ifFalse: ['alternative block'] ifTrue: ['alternative block2']) = 'alternative block2'.
+testCopying
+	self assert: #hello copy == #hello.
+	self assert: #hello deepCopy == #hello
+!
+
+testIsSymbolIsString
+	self assert: #hello isSymbol.
+	self deny: 'hello' isSymbol.
+	self deny: #hello isString.
+	self assert: 'hello' isString
 ! !
 
-TestCase subclass: #DictionaryTest
-	instanceVariableNames: ''
+Object subclass: #ObjectMock
+	instanceVariableNames: 'foo bar'
 	category: 'Kernel-Tests'!
 
-!DictionaryTest methodsFor: 'tests'!
+!ObjectMock methodsFor: 'not yet classified'!
 
-testPrintString
-	self
-		assert: 'a Dictionary(''firstname'' -> ''James'' , ''lastname'' -> ''Bond'')' 
-		equals: (Dictionary new 
-                         	at:'firstname' put: 'James';
-                        	at:'lastname' put: 'Bond';
-                        	printString)
+foo
+	^foo
 !
 
-testEquality
-	| d1 d2 |
-
-	self assert: Dictionary new = Dictionary new.
-		
-	d1 := Dictionary new at: 1 put: 2; yourself.
-	d2 := Dictionary new at: 1 put: 2; yourself.
-	self assert: d1 = d2.
+foo: anObject
+	foo := anObject
+! !
 
-	d2 := Dictionary new at: 1 put: 3; yourself.
-	self deny: d1 = d2.
+TestCase subclass: #UndefinedTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
 
-	d2 := Dictionary new at: 2 put: 2; yourself.
-	self deny: d1 = d2.
+!UndefinedTest methodsFor: 'tests'!
 
-	d2 := Dictionary new at: 1 put: 2; at: 3 put: 4; yourself.
-	self deny: d1 = d2.
+testIsNil
+	self assert: nil isNil.
+	self deny: nil notNil.
 !
 
-testDynamicDictionaries
-	self assert: #{'hello' -> 1} asDictionary = (Dictionary with: 'hello' -> 1)
+testIfNil
+	self assert: (nil ifNil: [true]) equals: true.
+	self deny: (nil ifNotNil: [true]) = true.
+	self assert: (nil ifNil: [true] ifNotNil: [false]) equals: true.
+	self deny: (nil ifNotNil: [true] ifNil: [false]) = true
 !
 
-testAccessing
-	| d |
+testCopying
+	self assert: nil copy equals: nil
+!
 
-	d := Dictionary new.
+testDeepCopy
+	self assert: nil deepCopy = nil
+! !
 
-	d at: 'hello' put: 'world'.
-	self assert: (d at: 'hello') = 'world'.
-	self assert: (d at: 'hello' ifAbsent: [nil]) = 'world'.
-	self deny: (d at: 'foo' ifAbsent: [nil]) = 'world'.
+TestCase subclass: #PointTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
 
-	d at: 1 put: 2.
-	self assert: (d at: 1) = 2.
+!PointTest methodsFor: 'tests'!
 
-	d at: 1@3 put: 3.
-	self assert: (d at: 1@3) = 3
+testAccessing
+	self assert: (Point x: 3 y: 4) x equals: 3.
+	self assert: (Point x: 3 y: 4) y equals: 4.
+	self assert: (Point new x: 3) x equals: 3.
+	self assert: (Point new y: 4) y equals: 4
 !
 
-testSize
-	| d |
-
-	d := Dictionary new.
-	self assert: d size = 0.
-
-	d at: 1 put: 2.
-	self assert: d size = 1.
+testAt
+	self assert: 3@4 equals: (Point x: 3 y: 4)
+!
 
-	d at: 2 put: 3.
-	self assert: d size = 2.
+testEgality
+	self assert: 3@4 = (3@4).
+	self deny: 3@5 = (3@6)
 !
 
-testValues
-	| d |
+testArithmetic
+	self assert: 3@4 * (3@4 ) equals: (Point x: 9 y: 16).
+	self assert: 3@4 + (3@4 ) equals: (Point x: 6 y: 8).
+	self assert: 3@4 - (3@4 ) equals: (Point x: 0 y: 0).
+	self assert: 6@8 / (3@4 ) equals: (Point x: 2 y: 2)
+!
 
-	d := Dictionary new.
-	d at: 1 put: 2.
-	d at: 2 put: 3.
-	d at: 3 put: 4.
+testTranslateBy
+	self assert: 3@4 equals: (3@3 translateBy: 0@1).
+	self assert: 3@2 equals: (3@3 translateBy: 0@1 negated).
+	self assert: 5@6 equals: (3@3 translateBy: 2@3).
+	self assert: 0@3 equals: (3@3 translateBy: 3 negated @0).
+! !
 
-	self assert: d values = #(2 3 4)
-!
+TestCase subclass: #RandomTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
 
-testKeys
-	| d |
+!RandomTest methodsFor: 'tests'!
 
-	d := Dictionary new.
-	d at: 1 put: 2.
-	d at: 2 put: 3.
-	d at: 3 put: 4.
+textNext
 
-	self assert: d keys = #(1 2 3)
+	10000 timesRepeat: [
+			| current next | 
+			next := Random new next.
+			self assert: (next >= 0).
+			self assert: (next < 1).
+			self deny: current = next.
+			next = current]
 ! !
 
-TestCase subclass: #StringTest
-	instanceVariableNames: ''
+TestCase subclass: #ClassBuilderTest
+	instanceVariableNames: 'builder theClass'
 	category: 'Kernel-Tests'!
 
-!StringTest methodsFor: 'tests'!
+!ClassBuilderTest methodsFor: 'running'!
 
-testJoin
-	self assert: 'hello,world' equals: (',' join: #('hello' 'world'))
+setUp
+	builder := ClassBuilder new
 !
 
-testStreamContents
-	self 
-		assert: 'hello world' 
-		equals: (String streamContents: [:aStream| aStream 
-                                                 					nextPutAll: 'hello'; space; 
-                                                 					nextPutAll: 'world'])
+tearDown
+	theClass ifNotNil: [Smalltalk current removeClass: theClass. theClass := nil]
 !
 
-testIncludesSubString
-	self assert: ('amber' includesSubString: 'ber').
-	self deny: ('amber' includesSubString: 'zork').
+testClassCopy
+	theClass := builder copyClass: ObjectMock named: 'ObjectMock2'.
+	self assert: theClass superclass == ObjectMock superclass.
+	self assert: theClass instanceVariableNames == ObjectMock instanceVariableNames.
+	self assert: theClass name equals: 'ObjectMock2'.
+	self assert: theClass package == ObjectMock package.
+	self assert: theClass methodDictionary keys equals: ObjectMock methodDictionary keys
 !
 
-testEquality
-	self assert: 'hello' = 'hello'.
-	self deny: 'hello' = 'world'.
+testInstanceVariableNames
+	self assert: (builder instanceVariableNamesFor: '  hello   world   ') equals: #('hello' 'world')
+! !
 
-	self assert: 'hello'  = 'hello' yourself.
-	self assert: 'hello' yourself = 'hello'.
+TestCase subclass: #SetTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
 
-	"test JS falsy value"
-	self deny: '' = 0
-!
+!SetTest methodsFor: 'tests'!
 
-testCopyWithoutAll
-	self 
-		assert: 'hello world' 
-		equals: ('*hello* *world*' copyWithoutAll: '*')
-!
+testUnicity
+	| set |
+	set := Set new.
+	set add: 21.
+	set add: 'hello'.
 
-testAt
-	self assert: ('hello' at: 1) = 'h'.
-	self assert: ('hello' at: 5) = 'o'.
-	self assert: ('hello' at: 6 ifAbsent: [nil]) = nil
-!
+	set add: 21.
+	self assert: set size = 2.
+	
+	set add: 'hello'.
+	self assert: set size = 2.
 
-testAtPut
-	"String instances are read-only"
-	self should: ['hello' at: 1 put: 'a'] raise: Error
+	self assert: set asArray equals: #(21 'hello')
 !
 
-testSize
-	self assert: 'smalltalk' size equals: 9.
-	self assert: '' size equals: 0
+testAt
+	self should: [Set new at: 1 put: 2] raise: Error
 !
 
 testAddRemove
-	self should: ['hello' add: 'a'] raise: Error.
-	self should: ['hello' remove: 'h'] raise: Error
-!
+	| set |
+	set := Set new.
+	
+	self assert: set isEmpty.
 
-testAsArray
-	self assert: 'hello' asArray = #('h' 'e' 'l' 'l' 'o').
-! !
+	set add: 3.
+	self assert: (set includes: 3).
 
-TestCase subclass: #ArrayTest
-	instanceVariableNames: ''
-	category: 'Kernel-Tests'!
+	set add: 5.
+	self assert: (set includes: 5).
 
-!ArrayTest methodsFor: 'testing'!
+	set remove: 3.
+	self deny: (set includes: 3)
+!
 
-testFirstN
-	self assert: {1. 2. 3} equals: ({1. 2. 3. 4. 5} first: 3).
+testSize
+	self assert: Set new size equals: 0.
+	self assert: (Set withAll: #(1 2 3 4)) size equals: 4.
+	self assert: (Set withAll: #(1 1 1 1)) size equals: 1
 ! !
 
 PackageTest subclass: #PackageWithDefaultCommitPathChangedTest

部分文件因文件數量過多而無法顯示