Mini-review of CafePress's direct-printed t-shirts

Posted by Tom Moertel Thu, 06 Jul 2006 03:48:00 GMT

As you may recall from a previous post, I set up a CafePress store to sell LectroTest Robot–branded stuff such as t-shirts, hats, mouse pads, magnets, and so on. CafePress does a good job of making their products appear to be of the highest quality, but I am naturally skeptical about such claims.

In particular, I wondered about their t-shirts. The results of their heat-transfer printing process – previously the only option – did not make me happy. Images with transparent areas revealed the transfer background, which over time yellowed and made the image seem to float on a sea of urine.

So when I set up The LectroTest Emporium, I specified the use of CafePress’s newer “direct-printing” process for t-shirts, hats, and every other product for which it was offered. Still, I wondered about the quality.

So I ordered up a LectroTest Robot t-shirt and put it to the test.

Test one: the eyeball and the scanner

When the t-shirt arrived, my initial impression was that it looked pretty darn good. The Robot came out perfectly, and even the pointy parts of the LectroTest lightning rendered without problems. The colors were true, if a little less saturated than I would have preferred.

Compared to silkscreen, the direct-printing process seems to produce results that are a bit less saturated and a bit less crisp. It’s like an airbrush artist rendered the Robot onto a billboard-sized shirt that was carefully shrunken to normal size.

Next, I threw the t-shirt on a flatbed scanner. The results are below. The first image is an overall view of the Robot logo. The second is a 300-dpi close-up of the lettering, where you can see the air-brush effect.

LectroTest Robot on CafePress white t-shirt

Close-up of LectroTest Robot on CafePress white t-shirt

Test two: the iron

To check for color offsetting, I turned the shirt inside out and ironed it on a full-steam, cotton setting. Throughout the ironing, the face of the front-side image was pressed into the white cotton of the back side of the shirt. Nevertheless, none of the ink migrated. The pure white remained pure white.

Test three: the washer

For the final test, I washed the shirt on a normal warm/cold cycle with a small load of other clothes. I then dried the clothing on a medium cycle. (CafePress recommends washing in cold water and drying on low, but nobody pampers their t-shirts like that, and so I tested under more typical conditions.)

When I took the shirt from the dryer, I didn’t see any signs of shrinkage or fading. To double-check, I ironed the shirt and threw it back on the flatbed scanner.

Doing a before-and-after comparison of the scans in the Gimp, I was able to see some shrinkage and fading (see image below). Top to bottom, the shirt shrank by about 4.5 percent; left to right, the shirt actually grew by about 1.8 percent. Minor fading was apparent, especially in the solid black areas. Neither the shrinkage nor the fading were concerning, however; both are typical for t-shirts, especially on the initial washing. The bottom line is that the shirt’s coolness was untarnished.

T-shirt before and after its first wash cycle

Summary

It’s a good t-shirt. It looked cool out of the box and fully captured the metallic fierceness of the beloved LectroTest Robot. The shirt handled a hot-steam ironing without any ink offsetting. It shrank and faded a bit on its initial wash, but neither change detracted meaningfully from the shirt. In sum, CafePress’s direct-printed t-shirts seem like the real deal: they look good and stand up to typical wear and washing.

Posted in , ,
Tags , , , ,
18 comments
no trackbacks
Reddit Delicious

LectroTest: new release, new talk, and the new LectroTest Emporium!

Posted by Tom Moertel Tue, 27 Jun 2006 18:21:00 GMT

LectroTest Robot

I have a bunch of LectroTest news. LectroTest, as you may know, is a specification-based, automatic testing system for Perl. It may look like Haskell’s QuickCheck, but it tastes like sweet, sweet Perl.

LectroTest 0.3500 was released

This version adds automatic tools for recording and playing back failures. Using them, you can automatically build regression-testing suites and incorporate them into your testing plan. All it takes is one new line of code:

use Test::LectroTest
    regressions => "regressions.txt";   # <-- that's it!

See the docs on CPAN for more.

My thanks to Steffen Müller, who suggested the feature and is already using it in cool stuff such as Number::WithError.

Slides from “Testing Tips with LectroTest” are now online

You can get the slides from my talk to the Pittsburgh Perl Mongers on 2006-06-14 here: Talk / Testing Tips with LectroTest. In the talk, I covered some of the newer LectroTest features, such as regression testing and Test::LectroTest::Compat, which lets you mix LectroTest with other Perl testing modules.

The LectroTest Emporium opens!

I have very little artistic ability. Nevertheless, alarming numbers of people seem to love the fiercely metallic mascot I created for LectroTest.

At the last Perl Mongers meeting, for example, people actually told me (somewhat sternly) I should put the adorable LectroTest Robot on t-shirts. I am now delighted to announce that I have taken their advice:

Introducing: The LectroTest Emporium

Some important points:

  • Yes, it’s a CafePress store
  • I’m not making any money on these things
  • I’m using direct printing, not heat-transfer printing, so the Robot won’t crack, feel stiff, or suffer from a yellowish transfer background. (CafePress has a comparison of the methods if you want the full details.)

Some items I have moral reservations about offering:

  • LectroTest Robot Teddy Bear - Who would be so reckless as to allow something as fierce and as powerful as the LectroTest Robot to come into direct contact with a defenseless, cuddly teddy bear?
  • LectroTest Robot Baby Bib - Actually, this is a great idea: your infant and the Robot exist in a symbiotic relationship. When your baby gets food all over the bib, the Robot will consume it (using a electrochemical process not entirely dissimilar to our human concept of “digestion”). Thus is the baby cleaned and the Robot fueled. It’s win-win.
  • LectroTest Robot Dog T-Shirt - I am fairly certain that the immense weight of the Robot would easily crush any smaller animal. This product strikes me as a very bad idea.

The T-shirts, on the other hand, are the robot’s meow. Check out the full collection at The LectroTest Emporium.

Posted in , , , ,
Tags , ,
1 comment
no trackbacks
Reddit Delicious

When worlds collide and then dance: Test::LectroTest meets Test::Builder

Posted by Tom Moertel Tue, 08 Feb 2005 17:00:00 GMT

It seems that LectroTest is picking up in popularity because I am starting to get regular requests and feedback. Recently, two related requests came in regarding something that I had put off: Figuring out how to merge specification-based testing, which samples thousands of trials per property check, with case-based testing, which runs one trial per case.

The rub is that case-base testing in Perl is managed by Test::Builder and a related family of modules that are designed to make that kind of testing easy. One convenience they offer is that calling test functions like cmp_ok not only performs a test, in this case a general comparison, but also reports the result of the test to the test harness.

So what happens if somebody wants to perform a cmp_ok test from within a LectroTest property specification? When the property is checked, LectroTest will test whether the property holds by sampling a thousand random trials (by default), each of which will end up calling cmp_ok. Can you see where this is going? Yup, the test harness will end up seeing one thousand separate tests instead of the single test of the property.

The solution to this problem, as to all problems of distinction, is hackery. The Test::* family of modules ends up filtering all calls to test functions such as cmp_ok down to the Test::Builder module’s ok method. This method does two things. First, it reports the result of the test to the test harness without giving us a chance to say otherwise. (Naughty!) Second, it returns the result of the test back to the original caller. As far as property checks are concerned, the first part is bad, and the second is good.

To get rid of the bad part, I redefine the ok method during property checks. I put the implementation into a new module, Test::LectroTest::Compat, that exports a single function holds. This function is used to inject a property check into a plain-old Test::Simple- or Test::More-style test plan. For example, here’s a test plan that uses the new module:

use Test::More tests => 2;
use Test::LectroTest::Compat;

my $prop_nonnegative = Property {
    ##[ x <- Int, y <- Int ]##
    cmp_ok(my_function( $x, $y ), '>=', 0);
}, name => "my_function output is non-negative" ;

holds( $prop_nonnegative ); # assert that the prop holds
cmp_ok( 0, '<', 1, "trivial 0<1 test" ); # a "normal" assertion
# ... and so on ...

What does holds do when called? It redefines Test::Builder’s ok method, runs the property-check trials, restores ok, and finally reports the property check’s result via the newly-restored ok. From there, Test::Builder takes over and does the magic necessary to incorporate the result into the test session’s TAP output.

The code that does all this is as follows:

sub holds {
    my ($diag_store, $results) = check_property(@_);
    my $success = $results->success;
    (my $name   = $results->summary) =~ s/^.*?- /property /;
    $Test->ok($success, $name);
    my $details = $results->details;
    $details =~ s/^.*?\n//;     # remove summary line
    $details =~ s/^\# /    /mg; # replace commenting w/ indent
    $Test->diag(@$diag_store) if @$diag_store;
    $Test->diag($details) if $details;
    return $success;
}

sub check_property {
    no strict 'refs';
    no warnings;
    my $diag_store = [];
    my $property = shift;
    local *Test::Builder::ok = \&disconnected_ok;
    local *Test::Builder::diag = sub { shift; push @$diag_store, @_ };
    return ( $diag_store, 
             Test::LectroTest::TestRunner->new(@_)->run($property) );
}

sub disconnected_ok { $_[1] ? 1 : 0 }

You can see that there is one extra bit of hackery going on. I also redefine Test::Builder’s diag method to capture any diagnostic output that may be emitted during the trials. Typically, this occurs only when a trial fails, and in that case the output is almost certainly worth passing back to the user in context. To ensure that the user sees it in context, I hold on to the captured output until the property check is complete and then roll it into the normal LectroTest diagnostic output. It looks great:

not ok 3 - property 'x is a natural number' falsified in 2 attempts
#     Failed test (t/compat.t at line 32)
#     '0'
#         >
#     '0'
#     Counterexample:
#     $x = 0;

In the first part you see the typical cmp_ok output that the assertion 0 > 0 failed. The second part is the LectroTest counterexample that shows at what part of the test space the assertion failed.

It takes some complicated footwork, but the resulting dance is beautiful. To see two markedly different testing systems – and in some ways markedly different testing philosophies – working in step with one another is gratifying. I suspect that most real-world testing problems can be solved better by a combination of the two approaches than by either alone. Thus I am especially happy about this integration.

After some more refinement, I am going to incorporate Test::LectroTest::Compat into the main distribution. For now, you can get a copy in the LectroTest/FAQs section of the Community Projects site.

Posted in ,
Tags , ,
no comments
no trackbacks
Reddit Delicious

LectroTest: An automatic, specification-based testing tool for Perl

Posted by Tom Moertel Fri, 10 Sep 2004 16:00:00 GMT

Just a quick note to mention LectroTest, a Perl project I have been working on recently. It’s inspired by QuickCheck for the Haskell programming language. The motivation is that traditional unit testing requires programmers to spell out each and every case to test, which seems like an awful lot of work, much of which probably isn’t necessary. Even so, the payoff of unit testing is real, and we ought to do it. Thus the goal becomes to reduce the pain while keeping the gain.

Rather than working at the level of individual test cases, why not tell the computer about the shape of the “test space” and let the computer generate the cases automatically? That’s what LectroTest does. You declare properties and assert that they hold over a certain test space. LectroTest then generates random cases from within the space and tests your assertion for each. If LectroTest is able to “break” whatever you’re testing, it emits a counterexample that you can feed back into your code to debug the error. (Counterexamples also make for nice regression tests.)

If you write code in Perl and want another option for testing your code, give LectroTest a look.

LectroTest logo robot

Posted in , ,
Tags , ,
no comments
no trackbacks
Reddit Delicious