altre destinazioni

ultimi post

ultimi commenti

tag principali

archivi

powered by

  • WPFrontman + WP

friends

copyright

  • © 2004-2011
    Ludovico Magnocavallo
    tutti i diritti riservati

HTML Dynamic TestRunner for PHPUnit

17 settembre 2003

Yesterday I set up to write unit tests for a few PHP classes I’m refactoring. Given my usual tendency to set aside serious tasks and concentrate on eye candy, after a few tests I decided to write my own test runner (something I’ve done at least twice before, never storing away the code for later use).

My test runner builds on a few assumptions:

  • the tests live in a web accessible directory
  • every php file in the directory with a name starting with test is a test case
  • every test file contains one case class extending PHPUnit_TestCase
  • every test class has the same name as the file where it resides
  • test cases are all the methods of the class whose names start with test
  • you run tests and see results with a web browser

The main test runner features are:

  • conditional execution of one or more test cases based on an HTML form
  • run only/exclude a test with a single click of the mouse
  • display aggregate test results by suite, showing counts for successes/failures and a warning indicator if any have been raised
  • optionally expand test results to show results/failures for single test cases
  • remember each suite visibility status (collapsed/expanded) for subsequent runs
  • collect PHP warnings emitted during each test case run and display them under the appropriate test suite

I made a few screenshots, showing a collapsed view of all available suites, the same for a single suite, with a warning indicator, and one suite expanded, showing test cases results and warnings.

The DynamicTestRunner code only needs to include the PEAR version of PHPUnit. Using a templating engine would have made the code more understandable, but at the cost of introducing a dependency.

If you want to preserve the option of being able to run each test file on its own, you can test if it has been called by testRunner with a simple if statement at the end of each test file (substituing of course testEntities with the name of the class declared in the file):

if (!isset($_SERVER['SCRIPT_FILENAME']) ||
    $_SERVER['SCRIPT_FILENAME'] == __FILE__) {
    $suite = new PHPUnit_TestSuite('testEntities');
    $result = PHPUnit::run($suite);
    echo $result->toString();
}

Lintel in the Enterprise

16 settembre 2003

Tonight, while trying to scan very old (100 yrs or so) negatives on my cheap ScanJet 3400c, I managed to read the very good article The Mad Hatter meets the MCSE, mentioned on a Slashdot post.

As I wrote in a past entry, I saw Sun Rays and MadHatter at Sun’s Milan offices a few weeks ago, and I was deeply impressed. This article examines in detail the impact of introducing a Lintel architecture in the Enterprise.

What I liked most from tonight’s quick read of this article (gonna read and summarize it for the big shots tomorrow at the office) are a few well-made points:

  • a Linux integration in the enteprise is a potential and very expensive failure, if it has to adapt to a Windows-based infrastructure
  • a Unix-based architecture is unlikely to evolve in Windows or Mainframe centric environments due to cultural differences between the two worlds
  • Sun’s Unix Business Architecture (UBA) has a tremendous potential and could change the way enterprises design and manage their IT infrastructures

Definitely a recommended reading.

Search engines are stupid

9 settembre 2003

Hmmm…maybe people do stupid searches on them. I was looking at the google searches people come on my site from, and noticed a good one: x x x stuff (without the spaces of course). I promptly opened it, and…wow I’m in 7th position, all thanks to a masked email address in my post on the J editor. Due to insistent requests from my gf, I changed the email address to to show z characters instead of x.

Removing unused css classes

6 settembre 2003

One of the things I like best of Python is the interactive console. I often use it to do quick manipulations on text files, and every time I wonder how I did manage before learning Python, when I wrote Perl or PHP scripts for similar things (yes I know that Perl has useful command line options for stuff like that, but with the Python console you can poke around and see the data you’re manipulating interactively, get help on commands, etc.).

So today I set to the task of removing unneeded CSS classes from a huge HTML file I did not produce myself.

Getting the data from a file is a one-liner:

/-(ludo@pippozzo)-(27/pts)-(15:44:06:Sat Sep 06)--
-($:~)-- python
Python 2.3 (#1, Aug  5 2003, 15:11:52)
[GCC 3.2.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> all = file('xxxxxxxxxx.html', 'r').read()

Then we import the re module and obtain a list of all css classes used in the file, removing duplicates:

>>> import re
>>> r = re.compile('class="([^"]+)"')
>>> styles = [s for s in r.findall(all) if s not in locals()['_[1]'].__self__]

The duplicate removal comprehension looks like a clever Perlish hack, but I’m in the console and it’s nice to be able to do everything in one line. I copied it from the Python Cookbook entry The Secret Name of List Comprehensions by Chris Perkins, who warns that It should come as no surprise to anyone that this is a totally undocumented, seat-of- your-pants exploitation of an implementation detail of the Python interpreter. There is absolutely no guarantee that this will continue to work in any future Python release.

Now that we have the list of classes in use, we can remove unneeded ones and save the processed content on the original file:

>>> r = re.compile(r"""(?ms)^(S*.(S+)s+{[^}]+}n)""")
>>>
>>> for style in r.findall(all):
...     if not style[1] in styles:
...             all = all.replace(style[0], '')
...
>>> file('xxxxxxxxxx.html', 'w').write(all)

Storing the styles in a dictionary is more efficient (not that it matters in this quick console run), and eliminates the need of using the duplicate removal hack. Here is a version using a dictionary:

>>> import re
>>> all = file('xxxxxxxxxx.html', 'r').read()
>>> r = re.compile('class="([^"]+)"')
>>> styles = {}
>>> for s in r.findall(all):
...     styles[s] = None
...
>>> r = re.compile(r"""(?ms)^(S*.(S+)s+{[^}]+}n)""")
>>> for style in r.findall(all):
...     if not style[1] in styles:
...             all = all.replace(style[0], '')
...
>>> file('xxxxxxxxxx.html', 'w').write(all)

update: the lines above worked for the particular file I was editing, a general solution would probably need a few changes:

  • In the second regexp, used to identify style class declarations, I assume the class identifier is anchored at the beginning of a line, which is not always the case
  • I look for style class declarations in the whole file, which is pretty pointless (but saves typing a few lines of code in the console and works for the specific HTML file in question); style class declarations are obviously inside a <style></style> block, so it’s better to limit the scope of the second findall() to the contents of the style block(s), speeding up the search/replace and reducing the chance of errors in the regexp match (for example, matching blocks of C/Java/PHP source in the body of the document)
  • maybe use a scanner object instead of the second findall, and replace using the match position, as Fredrik Lundh explains in Using Regular Expressions for Lexical Analysis

Text Processing in Python

5 settembre 2003

My current technical reading is the excellent book Text Processing in Python by David Mertz. In chapter 1 David expresses with his usual clarity a couple of concepts I usually unconsciously follow in my Python programming, but which are important enough to be repeat here as a reminder to myself.

[...] an important principle of Python programming makes types less important than programmers coming from other languages tend to expect. According to Python’s “principle of pervasive polymorphism” (my own coinage), it is more important what an object does than what it is.

David then proceeds to describe a few practical cases where pervasive polymorphism is useful, like working on file-like objects.

One common way to test a capability in Python is to try to do something, and catch any exceptions that occur (then try something else).

One of the main reasons why I like Python so much compared to other languages is the incredible usefulness of its exception mechanism. After all, many of the things we experiment or learn in life we do by trial and error, and using this same method in programming just fits your brain.

Dumping Vars the PEAR way

4 settembre 2003

Since it was announced on the PEAR newsgroup a few years ago, I have been using the Var_Dump class by Frederic Poeydomenge as one of my favourite PHP development tools. Dumping variables at strategic places has always been a practical and effective (if a bit simple) method of debugging in PHP and other languages. Unfortunately, when you’re working with complex data or with class instances, using the echo construct or the var_dump function is not very useful, unless you go to great lengths to extract what you really need to display from your data.

Var_Dump is a class that assists you in exactly this task, extracting all available information from your data and displaying it in a variety of ways. It is the PHP analogous to the Python pprint module, and one could spend an interesting few minutes comparing the two very different PHP and Python solutions to dumping (or pretty printing, which is more what’s happening here) data.

In its simplest form, the Var_Dump class can be used through a single static method, and a few optional constants. At the other end of the scale, a Var_Dump instance can be customized through skins, color sets, and display options to tailor its output to your exact needs. In this brief document, we will show examples of its use through a static method, since it’s the one you most probably will resort to during development. More complex examples can be found on the author’s site.

We start by importing the class code, and setting up a few variables and a class instance, that we will feed to Var_Dump.

require_once 'Var_Dump.php';

$a = array(0,1,2,34);
$b = array('a'=>'something', 'b'=>0, 0=>'b', 'c'=>$a);

class B {}

class A extends B {
    var $a;
    var $b = 1;
    function a($a) {
        $this->a = $a;
    }
}

$a_inst = new A(2);

Once we have that out of the way, we start feeding our data to Var_Dump by calling its display method as a static class method. First the simple array, without passing any extra argument to display.

Var_Dump::display($a);

Our friendly class spits out the following output:

0 Long (0)
1 Long (1)
2 Long (2)
3 Long (34)

Nice, isn’t it? Ok, let’s start using the optional arguments to display, and feed it something a bit more complex.

Var_Dump::display($b, 'b');

The second argument we passed to display in this example is the name of a key not to display, mainly used to avoid printing deeply nested data structures. As we can see from the following output, Var_Dump does a remarkable job of printing multidimensional arrays.

a String[9]  (something)
b Not parsed ()
0 String[1]  (b)
c Array(4)

    + 0 Long (0)
    | 1 Long (1)
    | 2 Long (2)
    + 3 Long (34)

On to the class instance, and the third argument you can pass to display.

Var_Dump::display($a_inst, null, VAR_DUMP_DISPLAY_MODE_HTML_TABLE);

As you have probably guessed, the third argument controls the output generated by Var_Dump through a few self-explanatory constants:

  • VAR_DUMP_DISPLAY_MODE_TEXT
  • VAR_DUMP_DISPLAY_MODE_HTML_TEXT
  • VAR_DUMP_DISPLAY_MODE_HTML_TABLE

The output of our instance is pretty interesting, as Var_Dump squeezes all available bits of information from it, including its class and its base classes, if any.

Class name String[1] (a)
Parent class String[1] (b)
Class vars (2)
a Null (Null)
b Long (1)
Class methods (1)
0 String[1] (a)
Object vars (2)
a Long (2)
b Long (1)

The fourth, and last of the arguments you can pass to display is again a constant from a self-explanatory set:

  • VAR_DUMP_NO_CLASS_VARS
  • VAR_DUMP_NO_CLASS_METHODS
  • VAR_DUMP_NO_CLASS_INFO

Let’s see what happens if we feed our instance to display, by using the VAR_DUMP_NO_CLASS_INFO constant, and reverting to the simpler output.

Var_Dump::display($a_inst, null,
    VAR_DUMP_DISPLAY_MODE_HTML, VAR_DUMP_NO_CLASS_INFO);
Class name   String[1] (a)
Parent class String[1] (b)
Object vars  Array(2) 
           
    + a Long (2)
    + b Long (1)

That’s all for tonight, if you have suggestions for PHP topics you would like to read here, drop me a message.

Hominids

3 settembre 2003

Hominids

A few days ago I read that Robert J. Sawyer’s Hominids had won the 2003 Hugo Award as best novel, so I put aside Terry Pratchett’s Moving Pictures for a while, grabbed a copy of Hominids and started reading.

I finished the book tonight, and I have to say I am a bit disappointed. The book, as many sf/fantasy books or movies (one of my favourites being the movie Groundhog Day), is built around an interesting idea involving space or time. In Hominids, Sawyers imagines that somewhere in Earth’s past a duplicate universe split off from our own, where Neanderthal men evolved instead of our race.

Unfortunately, this idea is just about the only good thing I found in this book. The plot is mediocre, the characters lack depth and psychological introspection, and the artifices the author uses to bridge the language barrier between the two worlds are really simplistic. Moreover, a good part of the book deals with a court case between the Neanderthals, and I found the topic really boring (maybe it appeals to US and Canadian readers) and its development superficial.

What I (somewhat) liked in this book is its rythm, and the wealth of notions about quantum theory and anthropology. All in all, it’s not one of the worst books I have read lately, and if you liked Michael Crichton’s Sphere or his Jurassic books maybe you will find Hominids a good read, though a simplistic one.

update: Out of curiosity, I had a look at the Amazon reviews for Hominids, and among all the celebrative reviews there’s one by JR Dunn which is worth quoting

This is Wellsian didactic SF on the kindergarten level. Intelligent Neanderthals turn out to be bisexual, atheist Canadians, and are willing to tell us about. And tell us about it. And tell us about it. Passage unto page unto chapter. (And just think–this is the beginning of a trilogy.)

If that sounds like your thing, go to it. Otherwise, your time would be better spent reading… oh, the government-mandated cooking directions in chicken packages. You’ll learn a lot more of value there.

Ouch! Well said, and in far less words than I used. Glad to know I’m not the only one to think that this book is overrated.

Feed On Feeds

3 settembre 2003

my feedonfeeds hack

I noticed from my logs that somebody using feedonfeeds is subscribed to my blog. Feedonfeeds is a nice PHP aggregator/reader, written by Steve Minutillo.

After shopping around for a while for a news aggregator, I settled on feedonfeeds a couple of months ago for a couple of reasons:

  • it has very few dependencies (any version of MySQL is ok, and a sufficiently recent PHP)
  • it is a server-side aggregator, allowing me to read news from home/office/wherever
  • it installs in a couple of minutes anywhere you can put a few PHP files
  • it is easily customizable
  • it works =)

So I installed feedonfeeds, and staying up to date has become a joy.

Never satisfied, after a couple of days of use I decided I absolutely needed a few features that feedonfeeds was lacking. So I set about refactoring it, and the project turned out to be a full rewrite. As usual with these things, the result is a half-completed app, so that I now have the (minor) features I wanted, and lack most basic ones feedonfeeds provides out of the box. =)

My rewrite is template-based, and factors out most common operations (eg SQL statements etc) in a few classes, instead of using lots of functions. So far, I have:

  • a fully functional news reading page with save/read/unread flagging, paging by page and by date, etc. (the one you see in the picture above)
  • a half-working feeds page, showing subscribed feeds and their new/read/saved news counts, and controls to add/edit/remove a feed that get you nowhere =)
  • an improved SQL schema, using InnoDB tables support for foreign keys
  • a new Python backend based on Mark Pilgrim’s ultra-liberal feed parser, supporting the parser’s use of HTTP features (If-None-Match and If- Modified-Since headers when requesting an RSS feed, and parsing the ETag and Last-Modified headers) to limit transfers; the uhm “backend” is an amazing 75 lines of code, including a 20 or 30 lines string containing the SQL schema =)

update: I finally managed to add the most important missing functionality to my feedonfeeds rewrite, and package it.