<?xml version='1.0' encoding='UTF-8' ?>
<rss version="2.0" xml:base="http://www.cincomsmalltalk.com/userblogs/cst/" xmlns:admin="http://webns.net/mvcb/" xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:icbm="http://postneo.com/icbm" xmlns:includedComments="http://www.laudably.com/rss2-comments" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
	<channel>
		<title>CST Tech Tips: category: general</title>
		<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView</link>
		<description>CST Tech Tips</description>
		<webMaster>mkobetic@cincom.com</webMaster>
		<lastBuildDate>Mon, 29 Mar 2010 13:17:46 GMT</lastBuildDate>
		<image>
			<url>/images/cst_small.jpg</url>
			<title>CST Tech Tips</title>
			<link>http://www.cincomsmalltalk.com/userblogscst/blogView</link>
			<height>50</height>
			<width>81</width>
		</image>
		<admin:generatorAgent rdf:resource="/CincomSmalltalkWiki/Silt"></admin:generatorAgent>
		<admin:errorReportsTo rdf:resource="mailto:mkobetic@cincom.com"></admin:errorReportsTo>
		<dc:language>en-us</dc:language>
		<dc:creator>Cincom Smalltalk Engineering</dc:creator>
		<dc:rights>Copyright 2005 Cincom Systems, Inc.</dc:rights>
		<dc:date>2010-03-29T13:17:46-05:00</dc:date>
		<icbm:latitude>39.150000</icbm:latitude>
		<icbm:longitude>-84.516667</icbm:longitude>
		<item>
			<title>ResourcefulTestCaseToo</title>
			<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView?showComments=true&amp;printTitle=ResourcefulTestCaseToo&amp;entry=3447321465</link>
			<category>general</category>
			<pubDate>Mon, 29 Mar 2010 13:17:45 GMT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p>

<p>&lt;div&gt;</p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;</p>

<p><span style="white-space: pre;"> </span>Good while ago I posted&nbsp;</p>

<p><span style="white-space: pre;"> </span>&lt;a href="http://www.cincomsmalltalk.com/userblogs/cst/blogView?entry=3356098418"&gt;ResourcefulTestCase&lt;/a&gt;</p>

<p><span style="white-space: pre;"> </span> talking about a simplified pattern for test resources in the context of SUnit. Basic idea was that if you tend to group your test cases around their required resource you often end up with a package where many TestCase classes are mirrored with TestResource classes one-to-one. In this situation it is more convenient to simply use the class side of the TestCase class as its resource and cut the amount of classes by half. Moreover, various resource aspects can be placed into class side variables and conveniently accessed from instance side test methods.</p>

<p><span style="white-space: pre;"> </span>&lt;/p&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;Recently I started using SUnitToo and wanted to try the same sort of pattern there. It turned out to be so simple, that it's not even worth adding a dedicated abstract TestClass to emulate the pattern.&lt;/p&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;To declare that a test class is its own resource simply add following (rather obvious) class method&lt;/p&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;pre&gt;resources</p>

<p>&nbsp;</p>

<p><span style="white-space: pre;"> </span>^Array with: self</p>

<p>&lt;/pre&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;Two more methods are needed to make the resource work: #isAvailable and #reset. They can be directly used to for set-up and tear-down, although note that #isAvailable must return a Boolean. Just return true at the end of the method and you're set. You can return false to signal that resource failed to set-up but an exception will have the same effect.&lt;/p&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;Now, without repeating all the arguments, the original article recommends to use shared variables for various aspects of the resource. Here is the rest of an example of a hypothetical test resource:&lt;/p&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;pre&gt;isAvailable</p>

<p>&nbsp;</p>

<p><span style="white-space: pre;"> </span>TestDirectory := '/dev/shm/testing' asFilename.</p>

<p><span style="white-space: pre;"> </span>TestDirectory ensureDirectoryExists.</p>

<p><span style="white-space: pre;"> </span>self generateTestContentIn: TestDirectory.</p>

<p><span style="white-space: pre;"> </span>^true</p>

<p>&lt;/pre&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;And don't forget to nil out the shared variables in tear-down.&lt;/p&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;pre&gt;reset</p>

<p>&nbsp;</p>

<p><span style="white-space: pre;"> </span>UnixProcess shOne: 'rm -r ', TestDirectory asString.</p>

<p><span style="white-space: pre;"> </span>TestDirectory := nil.</p>

<p>&lt;/pre&gt;</p>

<p><span style="white-space: pre;"> </span></p>

<p><span style="white-space: pre;"> </span>&lt;p&gt;</p>

<p><span style="white-space: pre;"> </span>That's it. The only boilerplate code is the rather trivial and obvious 'self' in the&nbsp;</p>

<p><span style="white-space: pre;"> </span>&lt;span style="font-weight: bold"&gt;resources&lt;/span&gt;</p>

<p><span style="white-space: pre;"> </span> method.</p>

<p><span style="white-space: pre;"> </span>&lt;/p&gt;</p>

<p>&lt;/div&gt;</p>

</p>
</div>]]></description>
			<guid isPermaLink="false">3447321465</guid>
			<pingback:server>http://www.cincomsmalltalk.com/userblogs/cst/blog/servlet/CommentAPIPBServlet?guid=3447321465</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/userblogs/cst/blogView?guid=3447321465</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/userblogs/cst/servlet/CommentAPIServlet?guid=3447321465</wfw:comment>
		</item>
		<item>
			<title>F-Spot, Glorp and VisualWorks</title>
			<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView?showComments=true&amp;printTitle=F-Spot,_Glorp_and_VisualWorks&amp;entry=3436429236</link>
			<category>general</category>
			<pubDate>Mon, 23 Nov 2009 11:40:36 GMT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p>I've been using Linux as my primary desktop platform for some years now. I generally try to keep up with the releases and stick with the default choices as much as possible. Recently I tried to use F-Spot because it's the default photo manager for GNOME now. It's got some nice features and is generally OK, although not very flexible. Very much in the spirit of today's UI design dogmas ("You can't handle flexibility!"). Anyway, I noticed that F-Spot uses sqlite3 as its database, so I wasn't too afraid to spend some effort tagging pictures etc.</p>

<p>Recently, as I was upgrading my computers, I decided to move the pictures to a different location. Unfortunately F-Spot doesn't seem to provide a way to update its database accordingly. Poking around in the database it seemed to be fairly simple database update, so I decided to whip up a quick, Glorp based, database mapping and do the update with a script.</p>

<p>The database has a PHOTOS table with following definition:</p>

<pre>CREATE TABLE photos (

	id			INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 

	time			INTEGER NOT NULL, 

	base_uri		STRING NOT NULL, 

	filename		STRING NOT NULL, 

	description		TEXT NOT NULL, 

	roll_id			INTEGER NOT NULL, 

	default_version_id	INTEGER NOT NULL, 

	rating			INTEGER NULL, 

	md5_sum			TEXT NULL

);

</pre>

<p>The path to the picture is stored in the base_uri field, usually looking something like 'file:///home/user/Photos/...'. I needed to change all of them to something like 'file:///pub/photos....' instead. So, first I created a Photo class with a simplified version of the above:</p>

<pre>	id  database id

	time  time taken

	base_uri  location of the photo

	filename  location of the photo

	description  any notes

</pre>

<p>Mappings are defined on subclasses of DescriptorSystem, so I created one and started with description of the class model:</p>

<pre>classModelForPhoto: aModel



	aModel newAttributeNamed: #id.

	aModel newAttributeNamed: #time type: Timestamp.

	aModel newAttributeNamed: #base_uri type: String.

	aModel newAttributeNamed: #filename type: String.

	aModel newAttributeNamed: #description type: String.

</pre>

<p>then the table description.</p>

<pre>tableForPHOTOS: aTable



	(aTable createFieldNamed: 'id' type: (self fakeSequenceFor: aTable)) bePrimaryKey.

	(aTable createFieldNamed: 'time' type: platform int4) beIndexed.

	aTable createFieldNamed: 'base_uri' type: platform varchar.

	aTable createFieldNamed: 'filename' type: platform varchar.

	aTable createFieldNamed: 'description' type: platform text.

</pre>

<p>and finally the mapping between the two:</p>

<pre>descriptorForPhoto: aDescriptor



	| table |

	table := self tableNamed: 'PHOTOS'.

	aDescriptor table: table.

	(aDescriptor newMapping: DirectMapping) from: #id to: (table fieldNamed: 'id').

	(aDescriptor newMapping: DirectMapping) from: #base_uri to: (table fieldNamed: 'base_uri').

	(aDescriptor newMapping: DirectMapping) from: #filename to: (table fieldNamed: 'filename').

	(aDescriptor newMapping: DirectMapping) from: #time to: (table fieldNamed: 'time').

	(aDescriptor newMapping: DirectMapping) from: #description to: (table fieldNamed: 'description').

</pre>

<p>&nbsp;</p>

<p>With these in place I could try to connect to the database. For that I needed to provide the connection information, so I added 2 class side methods:</p>

<pre>newLogin



	^(Login new)

		database: SQLite3Platform new;

		connectString: (PortableFilename named: '$(HOME)/.config/f-spot/photos.db') asFilename asString.



newSession



	^self sessionForLogin: self newLogin

</pre>

<p>With this I could invoke #newSession and get a connected session back. Time to start experimenting with the database.</p>

<p>Reading a photo is easy:</p>

<pre>	session readOneOf: Photo.

</pre>

<p>To figure out what are all the places from which I've imported pictures I used this:</p>

<pre>	query := (Query read: Photo) retrieve: [ :e | e base_uri ].

	(session execute: query) asSet.

</pre>

<p>It reads all the base_uri values and puts them into a Set. A smarter database query can do this more efficiently, but this was fine as well in my database of about 6k pictures. I found out I imported pictures from two locations. I decided to deal with them one by one. To perform the update I ran the following:</p>

<pre>	photos := session read: Photo where: [ :p | p base_uri like: '%home/mk/Photos%' ].

	session modify: photos in: [

		photos do: [ :p | p base_uri: (p base_uri copyReplaceAll: 'home/mk/Photos' with: 'pub/photos') ] ].

</pre>

<p>It reads each photo with the selected location in base_uri and updates it with the new one. Then I did the same for the second location. The entire update operation took less than 20 seconds. Later I found out that there's a plugin for F-Spot for this sort of migration, but its comment said that it can take a few hours. I don't know how big a database they had in mind, but that sounds a bit excessive still.</p>

<p>Since then I fleshed out the mappings, created a Glorp Workbook so that it's more convenient for quick experiments (you get a toolbar button for easy access) and packed it all up. I published the package to the public repository as F-Spot, hoping it might be useful to someone else too. As far as future plans go, there really aren't any beyond finishing the mapping layer. One thing I'm considering is that I find the imports into F-Spot excruciatingly slow. I might use this package for that task instead.</p>

<p>&nbsp;</p>
</div>]]></description>
			<guid isPermaLink="false">3436429236</guid>
			<pingback:server>http://www.cincomsmalltalk.com/userblogs/cst/blog/servlet/CommentAPIPBServlet?guid=3436429236</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/userblogs/cst/blogView?guid=3436429236</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/userblogs/cst/servlet/CommentAPIServlet?guid=3436429236</wfw:comment>
		</item>
		<item>
			<title>WebSupport updates</title>
			<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView?showComments=true&amp;printTitle=WebSupport_updates&amp;entry=3373744164</link>
			<category>general</category>
			<pubDate>Wed, 28 Nov 2007 23:09:24 GMT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p>Our Seaside effort yields some useful byproducts including improvements to the, so far rather Spartan, WebSupport package. This package now provides HttpClient and HttpRequest extensions simplifying submission of HTML form data through HTTP POST method.</p>

<p>In general, form data can be submitted in a "url encoded" format in a simple, single-part HTTP request (content-type: application/x-www-form-urlencoded), or each data entry can be submitted as an individual part in a multipart HTTP request (content-type: multipart/form-data). Multipart messages are used when form data contains entries with relatively large values, for example when a form has external files attached to it for upload to the server. More information about HTML forms can be found at <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13" target="_parent">http://www.w3.org/TR/html401/interact/forms.html#h-17.13</a>.
</p>
<p>The default behavior of WebSupport extensions is to submit forms as simple requests. Form entries can be added individually using #addFormKey:value: message, or set at once using #formData: message which takes a collection of Associations. Note that #formData: replaces any previous form content. The following example
</p>
<PRE>	stream := String new writeStream.
 	(HttpRequest post: 'http://localhost/xx/ValueOfFoo')
		addFormKey: 'foo' value: 'bar';
		addFormKey: 'file'  value: 'myFile';
		writeOn: stream.
	stream contents
</PRE>
<p>yields this result:
</p>
<PRE>POST /xx/ValueOfFoo HTTP/1.1
Host: localhost
Content-type: application/x-www-form-urlencoded
Content-length: 19

foo=bar&file=myFile'
</PRE>
<p>An alternative way to post a form is through HttpClient, in this case the request gets automatically executed and the result is the response from the server.
</p>
<PRE>	HttpClient new
		post: 'http://localhost/xx/ValueOfFoo' 
		formData: (
			Array
				with: 'foo' -> 'bar';
				with:'file' -> 'myFile').
</PRE>
<p>To force the form to submit as a multipart message, send #beMultipart to the request at any point. Any previously added entries will be automatically converted to message parts. Note however that conversion of multipart messages back to simple messages is not supported, as it is not always possible without potentially losing information.
</p>
<PRE>	stream := String new writeStream.
 	(HttpRequest post: 'http://localhost/xx/ValueOfFoo')
		beMultipart;
		addFormKey: 'foo' value: 'bar';
		addFormKey: 'file'  value: 'myFile';
		writeOn: stream.
	stream contents
</PRE>
<p>and the result is
</p>
<PRE>POST /xx/ValueOfFoo HTTP/1.1
Host: localhost
Content-type: multipart/form-data;boundary="=_vw0.98992842109405d_="
Content-length: 183

--=_vw0.98992842109405d_=
Content-disposition: form-data;name=foo

bar
--=_vw0.98992842109405d_=
Content-disposition: form-data;name=file

myFile
--=_vw0.98992842109405d_=--
</PRE>
<p>File entries can be added using message #addFormKey:filename:source:. Adding a file entry automatically forces the message to become multipart to be able to capture both the entry key and the filename.
</p>
<PRE>	stream := String new writeStream.
	(HttpRequest post: 'http://localhost/xx/ValueOfFoo')
		addFormKey: 'foo' value: 'bar';
		addFormKey: 'text'  filename: 'text.txt' source: 'some text' readStream;
		writeOn: stream.
	stream contents
</PRE>
<p></p><PRE>POST /xx/ValueOfFoo HTTP/1.1
Host: localhost
Content-type: multipart/form-data;boundary="=_vw0.015112462460581d_="
Content-length: 247

--=_vw0.015112462460581d_=
Content-disposition: form-data;name=foo

bar
--=_vw0.015112462460581d_=
Content-type: text/plain;charset=utf_8
Content-disposition: form-data;name=text;filename=text.txt

some text
--=_vw0.015112462460581d_=--
</PRE>
<p>Adding a file entry attempts to guess the appropriate Content-Type for that part from the filename extension. If it doesn't succeed the content type is set to default, i.e application/octet-stream. File names with non ASCII character will be automatically encoded using UTF8 encoding. UTF8 will also be used for the file contents if the source is a character stream (as opposed to byte stream).
</p>
<p>Adding an entry to a multipart message returns the newly created part. That allows to modify any of the default settings or to add new ones. Here's an example changing the filename and file contents encoding to ISO8859-2:
</p>
<PRE>	stream := String new writeStream.
	request := HttpRequest post: 'http://localhost/xx/ValueOfFoo'.
	part := request addFormKey: 'czech'
				filename: 'k&#367;&#328;.txt'
				source: 'P&#345;&#xED;li&#xA8; &#xB8;lu&#357;ou&#269;k&#xFD; k&#367;&#328; &#xFA;p&#283;l &#271;&#xE1;belsk&#xE9; &#xF3;dy.' withCRs readStream.
	part headerCharset: #'iso-8859-2';
		charset: #'iso-8859-2'.
	request writeOn: stream.
	stream contents
</PRE><P></P>
<PRE>POST /xx/ValueOfFoo HTTP/1.1
Host: localhost
Content-type: multipart/form-data;boundary="=_vw0.74617905623567d_="
Content-length: 228

--=_vw0.74617905623567d_=
Content-type: text/plain;charset=iso-8859-2
Content-disposition: form-data;name=czech;filename="=?iso-8859-2?B?a/nyLnR4dA==?="

P&#xF8;&#xED;li&#xB9; &#190;lu&#xBB;ou&#xE8;k&#xFD; k&#xF9;&#xF2; &#xFA;p&#xEC;l &#xEF;&#xE1;belsk&#xE9; &#xF3;dy.
--=_vw0.74617905623567d_=--
</PRE>

<p>There's also an API to parse messages containing forms in any of the supported forms. Just send #formData to the HTTP message. The result is a collection of associations, the same form as the input to the #formData: message.
</p>
<PRE> 	(HttpRequest post: 'http://localhost/xx/ValueOfFoo')
		addFormKey: 'foo' value: 'bar';
		addFormKey: 'file'  value: 'myFile';
		formData
</PRE>
<p></p><PRE>OrderedCollection ('foo'->'bar' 'file'->'myFile')
</PRE>
<p>File entry values will be entire message parts so that all the associated information can be accessed.
</p>
<PRE>	request := (HttpRequest post: 'http://localhost/xx/ValueOfFoo')
		addFormKey: 'foo' value: 'bar';
		addFormKey: 'text'  filename: 'text.txt' source: 'some text' readStream;
		yourself.
	part := request formData last value.
	part contents
</PRE>
<p></p><PRE>some text</PRE>

<p>If you'd like to give the new code a try just load it up from the <a href="http://www.cincomsmalltalk.com/CincomSmalltalkWiki/PostgreSQL+Access+Page" target="_parent">public repository</a>.</p>
</div>]]></description>
			<guid isPermaLink="false">3373744164</guid>
			<pingback:server>http://www.cincomsmalltalk.com/userblogs/cst/blog/servlet/CommentAPIPBServlet?guid=3373744164</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/userblogs/cst/blogView?guid=3373744164</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/userblogs/cst/servlet/CommentAPIServlet?guid=3373744164</wfw:comment>
		</item>
		<item>
			<title>ResourcefulTestCase</title>
			<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView?showComments=true&amp;printTitle=ResourcefulTestCase&amp;entry=3356098418</link>
			<category>general</category>
			<pubDate>Tue, 08 May 2007 17:33:38 GMT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p>The core SUnit package provides support for shared test resources via the TestResource class. A TestCase that wants to use TestResources is expected to list all its resource classes in its class side #resources method. Individual test case methods then access the resources via the resource classes, usually as default, singleton instances. That provides potentially interesting levels of flexibility, however the access to the resources themselves is not exactly convenient. In my experience vast majority of cases involving TestResources either keep repeating the 'self resources first default blah' incantation over and over again, where blah is the name of the real resource the case cares about which is being managed in a blah instance variable of the corresponding TestResource subclass. A more palatable way is adding the same instance variables to the TestCase subclass as well and copying the resource pieces there in the TestCase>>setUp method. Then you can access the resources directly as instance variables in your test case methods. This way the test methods are clean again, but when you want to employ test resources you still have to go through the following sequence of steps:
</p>
<ol>
<li>create a TestResource subclass
<li>add it to the TestCase class>>resources method
<li>add the same set of instance variables to the TestCase subclass
<li>copy the contents of the TestResource default instance to the TestCase instance variables in
 TestCase>>setUp method
</ol>
<p>Naturally as you realize you're doing this over and over again, you start thinking, wouldn't it be nice if you didn't have to. My first thought was, what if the TestSuite that gets built out of a given TestCase subclass didn't simply create empty TestCase instances, but instead first created a prototype instance, invoke something like #suiteSetUp on it, which would allow to initialize the shared resources and put them directly into the instance variables of the case prototype. Then all the test cases would be built by simply copying the prototype instance and therefore would have the resource inst vars automagically initialized the same way as the prototype. Tear down could be performed by invoking #suiteTearDown on either the prototype or any of the cases. It doesn't really matter which one, you just have to make sure it is executed exactly once.
</p>
<p>Of course while I was enjoying myself following this thread of thought, I forgot one important detail. TestCase instances are not created just before the suite runs. They are often created much much earlier. That of course directly conflicts with the desire to initialize the resources just before they are needed and shutting them down right after the run is complete. I was just about to descend into yet another desperate attempt to rewrite most of SUnit when Alan Knight, who happened to be traveling with me at that moment, responded to my loud complaints with simple: "Just put them into class variables."</p>
<p>
And so the <strong>ResourcefulTestCase</strong> was born. It is an abstract TestCase subclass with simplified support for shared test resources. Instead of separate classes of test resources, it makes sure that if there are class side #setUp and #tearDown methods defined on the class, they run before and after the test suite that gets built out of this test class. This allows one to initialize and store shared resources in class side variables in the #setUp method. It's probably easiest to use shared class variables for easy access from the instance side test case methods. I also like that the capitalized first letter nicely highlights in the test code the difference between the shared resources and the private stuff in case instance variables. Obviously the resources need to be torn down in the class side #tearDown method. It is usually also desirable to nil out the variables as well so that the class doesn't hand on to garbage. The nilling out could be done automatically with a bit of meta-programming, but since it's often also important to finalize/close/release the resources properly as well, I figured it's better to force the user to deal with that, rather than facilitate potentially serious leaks with more automated magic. It's probably also a good idea to call super implementations of the setUp/tearDown methods so that case hierarchies work well.</p>
<p>Here's a quick summary of how to create a test case with resources:</p>
<ol>
<li> Make the test class a subclass of ResourcefulTestCase:
<PRE>
XProgramming.SUnit defineClass: #MyTest
	superclass: #{XProgramming.SUnit.ResourcefulTestCase}
	indexedType: #none
	private: false
	instanceVariableNames: ''
	classInstanceVariableNames: ''
	imports: ''
	category: 'My Tests'

</PRE>
<li>Add class variables for the shared resources.
<li>Add class side setUp method and initialize the test resources there
<PRE>
MyTest class>>setUp

	A := Object new.
	Client := HttpClient new connect: 'testserver'

</PRE>
<li> Add class side tearDown method releasing the resources
<PRE>
MyTest class>>setUp

	A := nil.
	Client close.
	Client := nil.

</PRE>
</ol>
<p>And that's it. All nicely and intuitively packaged in a single class. Now you can simply use the resources in your test methods:
</p>
<PRE>MyTest>>testResources

	self assert: A class == Object.
	self assert: (Client get: 'index.html') isSuccess

</PRE>
The supporting code is published in the public repository in a package called <strong>SUnit-SimpleResources</strong>
</div>]]></description>
			<guid isPermaLink="false">3356098418</guid>
			<pingback:server>http://www.cincomsmalltalk.com/userblogs/cst/blog/servlet/CommentAPIPBServlet?guid=3356098418</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/userblogs/cst/blogView?guid=3356098418</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/userblogs/cst/servlet/CommentAPIServlet?guid=3356098418</wfw:comment>
		</item>
		<item>
			<title>No End of Line End Confusion.</title>
			<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView?showComments=true&amp;printTitle=No_End_of_Line_End_Confusion.&amp;entry=3349018393</link>
			<category>general</category>
			<pubDate>Thu, 15 Feb 2007 18:53:13 GMT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p><div>  <p> It&#39;s interesting that even though it&#39;s now decades old we&#39;re still running into this fundamentally rather trivial problem. It is especially pronounced in heavily cross-platform environments like VisualWorks. As soon as you have multiple environments, e.g. Windows and Linux and you move text files between the two, you&#39;re pretty much guaranteed to run into files with doubled or tripled line-ends in them sooner or later. Often you can see both line-end conventions mixed up in the same file.  The purpose of this article is to provide a reasonably complete picture of what&#39;s going on in VisualWorks in this regard and how are we supposed to deal with that. Even seasoned smalltalkers sometimes miss some part of the whole picture, making it more difficult to deal with the consequences. </p> 	<p>&nbsp;</p><h3>What&#39;s going on?</h3><p>&nbsp;</p> <p> Here&#39;s a quick recapitulation. There are 3 line end conventions in common use: CR (MacOS), LF (Unix) and CRLF (Windows). CR and LF here refer to characters with ASCII code 13 and 10 respectively. This historical fact can have a profound effect on an environment with the ambition to have fully binary portable images across platforms. Let&#39;s say we try to emulate the platform specific line end convention, i.e. use characters CR and LF in String instances on Windows, just LF on Unix, etc. This would make binary portability pretty difficult. Whenever we move an image from Windows to Unix and start it up we would need to convert all the existing String instances from the CRLF convention to LF convention. What&#39;s worse it will effectively change the character size of many Strings. While that might be somewhat manageable (we already do something similar for platforms with different endianness) there are further implications. If strings get shortened, the positions of streams set up on top of them will suddenly be off as well. In fact any kind of &quot;pointer&quot; into the String will be potentially broken. That will be much harder to fix. And if it&#39;s not fixed, things will start breaking. Binary portability wouldn&#39;t really work. </p> <p> So the only alternative is to pick one convention and stick with it everywhere. Historically the choice has been CR. I don&#39;t know why, maybe there was certain affinity of the original Smalltalk-80 developers towards Macintosh platform back then. Ironically, we may eventually end up being the only environment keeping the CR convention as MacOS/X is moving Macs away from the CR convention towards the LF convention of it&#39;s Unix based core. Nevertheless, the important point is that in Smalltalk line ends in String instances should *always* be marked with character CR only, no matter what platform it&#39;s running on. While character LF is a perfectly valid character and it&#39;s pretty easy to construct a String with that character in it, a String with LFs is usually a sign of some kind of anomaly and you can be sure that some components of the vast Smalltalk library won&#39;t be able to cope with it. This is very important, so remember, <span style="text-decoration: underline">only CRs in your Strings ! </span>This simplification has other advantages too, things like reading a line of text from a stream becomes simply &quot;upTo: Character cr&quot; anywhere. </p> 	<p>&nbsp;</p><h3>Tools of the trade</h3><p>&nbsp;</p> <p> OK, now that&#39;s settled, what about strings that come from outside ? It&#39;s not a Smalltalk only world out there (not yet anyway) and the text files on your harddrive will usually use whatever is the native convention for a given platform. The key point here is that these strings are coming from &quot;outside&quot;. They should be converted to the Smalltalk convention (CR) as they are brought in. That&#39;s why Strings with LF characters in them are often a sign of a failure to convert properly. </p> <p> The most common method to bring a String in from outside is to use an <strong>ExternalStream</strong>. And indeed if you take a closer look at those, you&#39;ll see that they have a configurable <strong>lineEndConvention</strong>. Setting an ExternalStream to #lineEndCRLF means that if you are using it to read e.g. a file, it will automatically convert byte sequence #[13 10] into a single character CR. When writing into such stream, it will automatically produce byte sequence #[13 10] whenever it is given character CR. Note that it will write #[10] if you give it character LF instead and similarly it will give you an LF when reading if it encounters a standalone byte 10 (one that is not preceded by 13). This is all assuming the stream is in text mode which is the default mode. If the stream is set to binary mode, it will pass the byte Integers through as they are, without any conversions. But you&#39;ll be getting ByteArrays out of the stream, not Strings in that case. The last thing that the streams will do for you automatically is set a default line end convention based on the platform that the image is running on. So if you create an external stream on Linux, it will be set to #lineEndLF. On Windows it will be set to #lineEndCRLF, etc. </p> <p> There&#39;s another kind of streams that provide these capabilities, the <strong>EncodedStreams</strong>. Primary function of these is to convert bytes to characters according to a specified &#39;character encoding&#39;. Character encoding is an even bigger can of worms, but for the purpose of this discussion let&#39;s just focus on the fact that EncodedStreams provide line end conversion the same way as external streams. In fact you can set an external stream to binary mode, wrap an EncodedStream around it and you should get the same results as with the external stream in text mode. This kind of setup will be handy in cases where you need to deal with character encodings that aren&#39;t supported by the external streams. There are in fact only very few of those that are supported by external streams: ISO8859_1, MSCP1252 for older Windows versions, and few more obscure encodings. For anything else (e.g. UTF-8) you will need to use an EncodedStream. So it is actually quite important that the EncodedStream is polymorphic with ExternalStreams. </p> 	<p>&nbsp;</p><h3>When tools need a hand</h3><p>&nbsp;</p> <p> So far so good. We now know the tools that are available in the base image for dealing with line-end conversions. The automatic configuration for native platform convention usually works out just fine when you&#39;re dealing with a single platform. But what if you&#39;re accessing a file system from Windows that is shared with Linux ? These are the cases when you may need to intervene and set the line end convention appropriately yourself. </p> <p> There&#39;s also a &quot;pseudo&quot; convention #lineEndAuto which makes the stream do a quick scan of an initial portion of the stream to determine which lineEndConvention to use based on the actual contents. This however may not be feasible on some types of external streams, e.g. socket streams, because it requires reliable positioning capability. </p> <p> Yet another alternative is the following. Instead of insisting on a specific convention for the entire stream, we could simply convert any convention to CRs as the stream is being read. This is especially nice when you want to cleanup a text with mixed conventions. Moreover this is actually doable without any pre-scanning and therefore could work on any kind of stream, even stream that cannot be peeked and positioned. This functionality isn&#39;t available in the Base image though, so I&#39;m going to plug here my <strong>AutoLineEndStream</strong> which does exactly that. It can be found in the ComputingStreams package in the public repository. With this the following will evaluate to true: </p> <pre><br /><br />	stream := #[10 13 10 10 13 13] asString readStream.<br />	stream := AutoLineEndStream wrap: stream.<br />	stream contents = &#39;\\\\\&#39; withCRs<br /><br /><br /></pre> <p> Note that AutoLineEndStream wraps a character stream (a stream that provides and consumes characters), e.g. an internal character stream or an external or encoded stream in text mode. The reason for this is complexity of character encodings. Even characters CR and LF need to be encoded when they are converted to/from bytes, and the encoding isn&#39;t always just 13 or 10. A CR can be #[13 00] or #[00 13] in UTF-16 encoding depending on the endianness and it can get even worse with other encodings. In general case it is impossible to pick out CR and LF out of an encoded text without decoding the other characters as well. So making AutoLineEndStream work with bytes would force it deep into the character encoding issues. It is much simpler to leave this domain to EncodedStreams and operate on characters instead, suddenly its task becomes trivial. So if you need to read an external file simply keep the stream (external or encoded) in text mode, set it to #lineEndTransparent which means don&#39;t do any conversion (all CRs and LFs will be preserved), and wrap it in AutoLineEndStream. Here&#39;s the corresponding code: </p> <pre><br /><br />	stream := &#39;messed up file.txt&#39; asFilename readStream<br />	stream lineEndTransparent.<br />	stream := AutoLineEndStream wrap: stream.<br /><br /><br /></pre> <p>	 Note that #lineEndTransparent is actually equivalent to #lineEndCR, just named differently to emphasize the effective transparency of this mode, and in this case definitely expresses the intent better. </p> <p> I should also mention that AutoLineEndStream will perform the same conversion when writing. If you write a CR and then an LF into the stream, it will write only CR into the underlying stream. So if you happen to have a String with mixed up line ends in memory, simply writing it through an AutoLineEndStream should straighten that ou as well. The following should evaluate to true as well: </p> <pre><br /><br />	stream := String new writeStream.<br />	stream := AutoLineEndStream wrap: stream.<br />	stream nextPutAll: #[10 13 10 10 13 13] asString.<br />	stream contents = &#39;\\\\\&#39; withCRs<br /><br /><br /></pre> <p> That&#39;s all I can think of that is relevant to this topic. I believe the problem isn&#39;t particularly difficult to deal with once you have a good understanding of what is going on and what should be happening. I hope this article will help with that. Thanks for reading this far and if you have any corrections, suggestions, ideas, I&#39;ll be watching the comments eagerly. </p> </div>
</p></div>]]></description>
			<guid isPermaLink="false">3349018393</guid>
			<pingback:server>http://www.cincomsmalltalk.com/userblogs/cst/blog/servlet/CommentAPIPBServlet?guid=3349018393</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/userblogs/cst/blogView?guid=3349018393</pingback:target>
			<includedComments:comment-collection></includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/userblogs/cst/servlet/CommentAPIServlet?guid=3349018393</wfw:comment>
		</item>
		<item>
			<title>Welcome to the Cincom Smalltalk Engineering Blog!</title>
			<link>http://www.cincomsmalltalk.com/userblogs/cst/blogView?showComments=true&amp;printTitle=Welcome_to_the_Cincom_Smalltalk_Engineering_Blog!&amp;entry=3304857321</link>
			<category>general</category>
			<pubDate>Thu, 22 Sep 2005 15:55:21 GMT</pubDate>
			<description><![CDATA[<div xmlns="http://www.w3.org/1999/xhtml">
<p>We've set up a new blog for the Cincom Smalltalk engineering team - expect to find technical posts here that cut across the entire Cincom Smalltalk product line.  I'll be making some modifications to the blog server so that posts from some of the individual blogs get cross posted here automatically - that's going to take a little work to get right.  In the meantime, enjoy the new site!</p>
</div>]]></description>
			<guid isPermaLink="false">3304857321</guid>
			<pingback:server>http://www.cincomsmalltalk.com/userblogs/cst/blog/servlet/CommentAPIPBServlet?guid=3304857321</pingback:server>
			<pingback:target>http://www.cincomsmalltalk.com/userblogs/cst/blogView?guid=3304857321</pingback:target>
			<includedComments:comment-collection>
				<includedComments:comment>
					<includedComments:guid>blogView?showComments=true&amp;printTitle=Welcome_to_the_Cincom_Smalltalk_Engineering_Blog!&amp;entry=3304857321</includedComments:guid>
					<includedComments:puid>blogView?showComments=true&amp;printTitle=Welcome_to_the_Cincom_Smalltalk_Engineering_Blog!&amp;entry=3304857321</includedComments:puid>
					<includedComments:author>J Pfersich</includedComments:author>
					<includedComments:pubDate>2005-09-27T01:46:12-04:00</includedComments:pubDate>
					<includedComments:content>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt; I guess I'll be the first to say that this is a great idea! ;-)   
&lt;/p&gt;&lt;/div&gt;</includedComments:content>
					<includedComments:title></includedComments:title>
				</includedComments:comment>
			</includedComments:comment-collection>
			<wfw:comment>http://www.cincomsmalltalk.com/userblogs/cst/servlet/CommentAPIServlet?guid=3304857321</wfw:comment>
		</item>
	</channel>
</rss>

