Code for Concinnity

beautiful and elegant solutions


Get Selenium onChange to work cross browser

Seems like there are a lot of people struggling to get Selenium RC to robustly fire the onchange event, but many people have failed. I faced the same problem. In particular, IE was not behaving properly.

Today I finally found out the solution, which makes me feel quite stupid :P

1
2
3
4
5
6
7
8
9
    // JUnit syntax. Basically the idea is that you just need to
    // use runScript to force the event to fire
    // Selenium's fireEvent is broken

    // jQuery
    selenium.runScript("$('#MyInputElement').trigger('change')");

    // Vanilla JavaScript
    document.getElementById('MyInputElement').onchange();

There you go!

Published by kizzx2, on August 15th, 2010 at 11:41 pm. Filled under: Uncategorized Tags: , , , No Comments

Using Selenium RC’s test suite runner with Internet Explorer — the solution!

If you’ve tried to use Selenium RC with Internet Explorer, here’s a list of things you will go through, before you get frustrated:

  • Using the plain and simple *iexplore doesn’t work at all. Selenium says the session is expired or something along the lines of sessionId 864408 doesn't exist.

  • Most people would tell you to try *iexploreproxy, which sort of works (the browser starts) but sometimes won’t run (especially if your test contains the open command). It would say Access denied or something in the JavaScript error bar. Even if you try to disable all security settings and run the test as root, it wouldn’t bite.

  • Then you try *piiexplore, which works but would have tests mysteriously failing for some reason (sometimes pages can’t load and will time out in an error).

The Solution

The right way to do it is to use *iexploreproxy, but you need to do two things:

  • Before each test run, you need to clear the temporary files and cookies in IE. I use the Ruby script found here which worked like a charm. This would eliminate the JavaScript access denied error.

  • Run the test suite as Administrator. Otherwise, Selenium would fail to modify some registry value at the end and your test logs will not get written.

Probably nobody has figured this one out yet since I can find absolutely no solution on the net to talk about this. Here we go!

For your reference, here’s the commands I used to start Selenium:

1
2
> ruby clear_ie.rb
> java -jar /path/to/selenium.jar -htmlSuite *iexploreproxy http://root/url /path/to/testsuite.html /path/to/logfile.html
Published by kizzx2, on August 14th, 2010 at 2:01 pm. Filled under: Uncategorized Tags: , , , , , 12 Comments

Reading a Unicode (UTF16) file in Windows (C++)

I can’t believe it’s so convoluted. This is a step-by-step guide from how I discovered the Elegant Way to read a Unicode file in Windows — it’s only 4 lines!

(The Unicode file I’m referring here is what you get when you save a file as Unicode in Notepad — that’s little Endian UTF16)

For the impatient

1
2
3
4
5
6
7
wstring ReadUTF16(const string & filename)
{
    ifstream file(filename.c_str());
    stringstream ss;
    ss << file.rdbuf() << '\0';
    return wstring((wchar_t *)ss.str().c_str());
}

The problem

To read UTF16, one would expect to use the widechar variants from iostream:

1
2
3
4
5
// Failed attemp
wifstream file("file.utf8.txt");
wstringstream ss;
ss << file.rdbuf();
wstring result = ss.str();

However, the above code will give you bogus text.

The investigation

Why? If you debug it and look at memory, you will see ss.str().c_str() evaluates to something like this:

0x00367738  ff 00 fe 00 60 00 4f 00 7d 00 59 00

The first 4 bytes look strikingly suspicious! 0xfffe is the magic sequence (BOM) for little endian Unicode, yet it’s been broken up by ifstream into two wide-chars (4 bytes).

It turns out that iostream will try very hard to conform to the current codepage — something that’s so obscure about C++ that apparently nobody talks about (from my search). In most cases, the code page will be something Latin. iostream goes the extra mile to break up bytes into widechars, because it assumes all files it reads to be single-byte.

I heard you can actually tell iostream to treat the file as UTF16 instead. There is a setting somewhere probably related to (Click it, look 5 seconds and then come back) codecvt. OK, back? That’s definitely not something you want to touch just to read a damn file.

The solution

It turns to be quite anti-climatic, let’s look at our solution again:

1
2
3
4
5
6
7
wstring ReadUTF16(const string & filename)
{
    ifstream file(filename.c_str());
    stringstream ss;
    ss << file.rdbuf() << '\0';
    return wstring((wchar_t *)ss.str().c_str());
}

You see, basically what the above does is to tell iostream to read the file as a single byte file, but don’t break up the bytes into widechars (so things remain nicely packed) and we’ll do a hardcore conversion ourself. Problem solved.

Caveats

I didn’t bother to trace down where the 0xfffe went after the conversion — it just worked and I was done with it. I also suspect some garbage might be appended at the end of the text stream. Again, Worked For Me. In any case, just do some substring to crop out the parts you don’t want.

Why is it marked “Windows”?

This is marked Windows because the code above is not portable — many *nix platforms have sizeof(wchar_t) == 4. In general, most modern POSIX supports UTF8 natively through plain old char. You can also use the excellent libiconv which converts everything to everything in one function call — making all this fuss irrelevant.

Alternatives

If you deal with UTF8, you might want to check out UTF8-CPP. It probably also supports reading UTF16 but I couldn’t find a quick way to make it work. It’s less heavyweight than ICU — but who can beat 4 lines when you just want to read a darn file?

(UTF8-CPP does support reading UTF-16. Unfortunately it only supports converting it to UTF-8, which is something Windows can’t do conveniently)

Published by kizzx2, on August 3rd, 2010 at 12:15 am. Filled under: Interesting things Tags: , , , , , 1 Comment