Finding the API for a DLL

In my last post, because I had problems with the 64bit version of JScript not working with Quality Center 10, I went far and wide looking for a solution.  My first thought was that maybe it’s not called “TDApiOle80.TDConnection” anymore.  After all, this is QC version 10, not 8.  I just wanted to see what the class was called, but I had no way to look at the DLL.

Here’s what I did to fix that.

I installed the .NET SDK (just so that I could get a little file called ildasm.exe  The .NET disassembler.

That didn’t give me the object name, but I went ahead on the assumption that the name hadn’t changed.  I supposed I could have used “strings” if I had it installed.

I also tried using the following command to make sure that the DLL was loaded.

regsvr32 “c:\Program Files (x86)\Common Files\Mercury Interactive\Quality Center\OTAClient.dll”

It said it was

If you don’t have the QC OTA Api handy, you can get a basic view with ildasm

Advertisements

Connecting to HP/Mercury Quality Center from a client side script

Quality Center / Test Director has hooks for writing external scripts.  This is called the Open Test Architecture (OTA) These can run on the client using COM using the OTAClient.dll or from within Test Director as a VAPI-XP test case.

You can download OTAClient.dll by logging in to Test Director and going to Help->Add-in Page->HP Quality Center Client Side Setup. 

You are prompted to install this when you first log in to Test Director from a new computer, so you might already have OTAClient installed.   Alternately, you can just install HP Quality Center Connectivity with will install OTAClient.dll without all the client-side functionality.

Note that you need to disable Windows User Account Control (UAC) to use Quality Center.

The steps for disabling UAC are slightly different for Windows Vista.

You can create a Test Director connection with VBScript or JScript, using Ruby or Python COM, with a Java COM Bridge like JACOB.

In VBScript:

Dim qc

Dim qc
Set qc = CreateObject("TDApiOle80.TDConnection")

In JScript:

var qc = new ActiveXObject("TDApiOle80.TDConnection");

In Python:

import win32com
from win32com import client
td = win32com.client.Dispatch( "TDApiOle80.TDConnection" )

I’m using Windows 7 x64 so I can’t use the 64 bit WScript/Cscript executable.  By calling my script with the 32 bit version of CScript.exe it will work.  SysWOW64 will check to see if your COM object is 32 bit and use the correct interpreter.

C:\Windows\SysWOW64\cscript.exe qc_connect.js

see http://www.sqaforums.com/showflat.php?Number=479531

Likewise, with Python, you need to make sure that you have a 32 bit version of python installed, as well as 32 bit pywin32.

The important thing to remember is that you need to use the 32 bit version of each with OTAClient.dll

This was a pretty big source of headaches for me.

Trying to game the Pareto Principle

The Pareto Principle is a fancy name for the 80-20 rule.

I saw a tweet by @juixe (or rather a blog post mentioning the tweet) that said:

“Cut out the 20% from Pareto’s Principle from your process.”

So I did just that.

If 20% of the work takes 80% of the time, suppose you had a job that took 100 hours to accomplish.

80% of the work would be done in 20 hours.

The remaining 20% of the work will take the remaining 80 hours.

Now, it’s a given that you don’t know which 20% that is up front.  So if you cut hours across the board (or randomly, assuming an optimal distribution), you’d decrease work in an evenly distrubuted pattern.  That is 80% of your savings affects the easy part (or 16%) and 20% of your savings affects the hard part (or 4%).

The easy part (20 hours work) is thus reduced by 16% to 16.8 hours.

The hard part (80 hours work) is then reduced by 4% to 76.8 hours.

For a total savings of 6.4 hours work.

This shows why you shouldn’t try to cut scope.

Testing a temperature converter

I’m sure we all know the formula to convert Celsius to Fahrenheit, or convert Fahrenheit to Celsius.
It goes something like this:

celsius2fahrenheit = (temperature * 9/5) – 32
fahrenheit2celsius = (temperature – 32) * 5/9

I always forget and have to experiment a bit before I get the pluses, fives, and nines all in the right places — not to mention the correct spelling of f-a-h-r-e-n-h-e-i-t.

Luckily, I know 4 temperatures that I can test on scratch paper with this formula.  They are:

  1. The boiling point of water (212F or 100C)
  2. The freezing point of water (32F or 0C)
  3. Standard temperature (59F or 17C)
  4. Forty below (-40F and -40C)

Today, I decided to codify it in a PHP script when I saw this request on PeoplePerHour.com

PHP Code for a Celsius/Fahrenheit convertor

Now, I like to think I’m above doing someone’s homework for them (just barely), but I thought I’d take up the challenge.   I also decided I would use PHPUnit to write the tests and came up with this:

TempConverter.php

<?php

class TempConverter {
	public static function c2f($temp) {
		return $temp * 1.0 * 9/5 + 32;
	}
	public static function f2c($temp) {
		return ($temp -32) * 1.0 * 5/9;
	}
}

TestTempConverter.php

<?php

require_once('TempConverter.php');

class TempConverterTest extends PHPUnit_Framework_Testcase
{
	public function testInstantiation() {
		$obj = new TempConverter();
		$this->assertTrue($obj instanceof TempConverter);
	}

	public function testStandardTemp() {
		$standardF = 59;
		$standardC = 15;

		$this->assertEquals($F, TempConverter::c2f($standardC));
		$this->assertEquals($C, TempConverter::f2c($standardF));
	}

	public function testFreezing() {
		$freezingF = 32;
		$freezingC = 0;

		$this->assertEquals($freezingF, TempConverter::c2f($freezingC));
		$this->assertEquals($freezingC, TempConverter::f2c($freezingF));
	}

	public function testBoiling() {
		$boilingF = 212;
		$boilingC = 100;

		$this->assertEquals($boilingF, TempConverter::c2f($boilingC));
		$this->assertEquals($boilingC, TempConverter::f2c($boilingF));
	}

	public function testFortyBelow() {
		$fortyBelow = -40;

		$this->assertEquals($fortyBelow, TempConverter::c2f($fortyBelow));
		$this->assertEquals($fortyBelow, TempConverter::f2c($fortyBelow));
	}
}

After a bit of shuffling I figured out the righrt formulas, and got all my tests passing.

As luck would have it, I had pretty good coverage with my test data. Not just a wide range of temperatures, but a wide variety of inputs as well. I’ve got positive numbers, negative numbers, zero, and even a result with identical numbers. But what could I do to improve?

My first thought was that I knew one other number for comparison, absolute zero, the temperature at which atoms stop moving: zero Kelvin or -273C. A quick google search gave the Fahrenheit number -459.67F So I added this test case:

	public function testAbsoluteZero() {
		$absoluteZeroF = -459.67;
		$absoluteZeroC = -273;

		$this->assertEquals($absoluteZeroF, TempConverter::c2f($absoluteZeroC));
		$this->assertEquals($absoluteZeroC, TempConverter::c2f($absoluteZeroF));
	}

When I ran again, I got this message:

There was 1 failure:

1) TempConverterTest::testAbsoluteZero
Failed asserting that <double:-459.4> matches expected <double:-459.67>.

After a little head scratching (and a bit more googling) I learned that they’ve changed the bar, and 0 Kelvin is now precisely -273.15C. I fixed the test and ran it again, only to get this puzzling answer:

There was 1 failure:

1) TempConverterTest::testAbsoluteZero
Failed asserting that <double:-459.67> matches expected <double:-459.67>.

Now that was some odd behavior. Obviously my code was working, and I was getting the right result, but something was amiss. I tried this, which passed:

		$this->assertEquals($absoluteZeroF, round(TempConverter::c2f($absoluteZeroC), 2));

Clearly it was either a rounding in PHP or something wrong with float comparisons in PHPUnit.

But that’s not what I wanted to talk about.  I wanted to discuss how to structure tests. Let’s comment that out for now.

A common way of writing unit tests is to test each method in the system under test with one test method.  I could have written something like this:

	public function testC2F() {
		$standardF = 59;
		$standardC = 15;
		$freezingF = 32;
		$freezingC = 0;
		$boilingF = 212;
		$boilingC = 100;
		$fortyBelow = -40;
		$absoluteZeroF = -459.67;
		$absoluteZeroC = -273.15;
				
		$this->assertEquals($standardF, TempConverter::c2f($standardC));
		$this->assertEquals($freezingF, TempConverter::c2f($freezingC));
		$this->assertEquals($boilingF, TempConverter::c2f($boilingC));
		$this->assertEquals($fortyBelow, TempConverter::c2f($fortyBelow));
	}

	public function testF2C() {
		$standardF = 59;
		$standardC = 15;
		$freezingF = 32;
		$freezingC = 0;
		$boilingF = 212;
		$boilingC = 100;
		$fortyBelow = -40;
		$absoluteZeroF = -459.67;
		$absoluteZeroC = -273.15;
		
		$this->assertEquals($standardC, TempConverter::f2c($standardF));
		$this->assertEquals($freezingC, TempConverter::f2c($freezingF));
		$this->assertEquals($boilingC, TempConverter::f2c($boilingF));
		$this->assertEquals($fortyBelow, TempConverter::f2c($fortyBelow));
	}

This works reasonably well besides the duplication of test data (which could be solved with class constants), but the point I’m trying to make is that you can test a scenario better the other way. Then your test function describes your test scenario.

It could easily be refactored into a data driven test with a comment denoting the scenario, and an allowance for rounding errors:

	/**
	 * @dataProvider knownTemperatures
	 */
	public function testDataDrivenConversion($f, $c, $scenario) {
		$digits = 7;
		
		$this->assertEquals(round($c, $digits), round(TempConverter::f2c($f), $digits), $scenario);
		$this->assertEquals(round($f, $digits), round(TempConverter::c2f($c), $digits), $scenario);
	}
	
	public function knownTemperatures() {
		$tempuratures = array(
			array(59, 15, 'compare standard temperatures at standard pressure'),
			array(32, 0, 'compare the freezing point of water'),
			array(212, 100, 'compare the boiling point of water'),
			array(-40, -40, 'compare forty below zero (should be the same for both)'),
			array(-459.67, -273.15, 'compare absolute zero'),
			array(6, -14.44444444, 'compare a random number'),
		);
		
		return $tempuratures;
	}

The source code is available at:

http://one-shore.com/aaron/TempConverter.zip

Housing crisis is worse than I imagined

We all know there’s a “housing crisis”  and yeah, some people bought houses they shouldn’t have, but the real problem is with refinancing and home equity lines of credit (HELOCs.)  Here’s an example of a house I was looking at, and if typical (which I suspect it is) represents a tremendous problem.

The house was bought in 1998 by an investor who “flipped” it.  They sold it (presumably for a profit) in 1999 to the current owner for $215,000.  It’s in a desirable neighborhood in California and is in fairly good condition with a good sized yard.  Sounds reasonable so far.

The current owner is attempting a short sale.  Here’s the breakdown of their mortgage history:

They bought the home in 1999 for $215,000.

They had a second mortgage of $21,500 presumably for a 10% downpayment.  In all likelihood, they bought with 0% down.  They signed some papers saying that they would pay it off over 30 years.  Instead, this is what happened:

The current owner puchased the home in 1999 for $215,000.
A second mortgage was used for 10% downpayment of $21,500.
The mortgage was refinanced in 2002 for $181,000.
This could be considered the principal owed on the first mortgage (originally $193,450).
A line of credit (HELOC) was granted in 2002 for $50,000.
The first and second mortgage, plus line of credit were refinanced in 2003 for $270,000.
This is a $5000 profit, assuming no principal was paid.
Another line of credit was granted in 2005 for $183,900.
The mortgage and line of credit were refinancd in 2005 for $456,000
Assuming no payment, that’s an additional profit of $2700.
You can assume the differences in refinance were absorbed in fees.
That’s a total of $7700 profit for the lenders.
And a staggering $255,400 profit over 11 years for the buyer with zero investment.

That’s more than TWO HUNDRED AND FIFTY THOUSAND DOLLARS extracted from the property over 10 years, with effectively no principal payed.  No doubt some of that money was used to service the debt, and some of it was spent on improvements to the property, but we’re looking at more than 100% of the value of the home completely vanishing.

Sure, the lenders extracted $7700 in profit refinancing, but who’s the real bad guy here?