Tuesday, 15 August 2017

Busted or LuaUnit? Answered

I didn't have the time to complete a thorough evaluation of Busted and LuaUnit but have come to the conclusion that I will use Busted. Both Busted and LuaUnit work well and, given Lua's dynamic nature, I found it easy to write tests with them.

I came to my decision after going back to the Stockfetch tests after a gap of two or three months. It was much easier to work out what was being tested from the Busted tests than it was from the LuaUnit ones. It was because of the names that I had given the tests not any failing on LuaUnit's part.

So my choice was not made on a technical basis but because Busted encourages me to write more understandable tests.

I also found, in some cases, Busted's spies, stubs and mocks made for shorter test code than using Lua's flexibility with LuaUnit. On the other hand, LuaUnit tests seem to run much quicker than Busted's. Around ten times faster in my case.

Wednesday, 26 July 2017

Installing Raspbian x86 under Virtual Box on macOS host

I failed in my first attempt to install Raspbian x86 under Virtual Box hosted macOS. The problem was I hadn't enable PAE/NX for the virtual processor. I learnt this from Andrew Cotswold Jam Oakley's excellent instructions

Although written for installing Raspbian on a Windows-hosted Virtual Box, the instructions apply equally to a macOS.

One thing that Andrew's instructions didn't cover was sharing folders between the host and Raspbian. To do this you need to have installed the Virtual Box guest additions as described in Andrew's instructions and then setup the shared folder(s) in the Virtual Box settings for your Raspbian VM. The last thing is to set the correct permissions so that you can access the folders from the VM.

All that is needed is to add yourself to the group which controls the shared folder(s). Assuming your username is pi, you would need to run the following command:

  sudo adduser pi vboxsf

You will find your shared folders in the /media folder. The prefix sf_ will have been added to their names. 

Wednesday, 19 July 2017

Running Rebol under FreeBSD 11

Whilst it has not been updated for a long time, the FreeBSD version of Rebol will run under FreeBSD 11. You do have to install the system libraries that were current when the Rebol FreeBSD version was last updated. FreeBSD has a complete set of "compatibility" libraries. Rebol requires version 6. Here is the command to install them:

pkg install misc/compat6x

Sharing Folders between macOS and FreeBSD under Virtual Box

I use VirtualBox to host a number of guest operating systems on a Mac, mainly for testing. I write a few tests for the emerging Red programming language. Although still in the Alpha phase, Red runs under Windows, macOS, Linux and FreeBSD.

Windows and Linux are well supported by VirtualBox and after installing the VirtualBox Guest Additions you can share folders between the host and guest operating systems. (The additions also provide mouse integration, clipboard sharing and other sharing features). This allows me to keep a single copy of the Red git repository and access it from the different virtual machines.

Virtual Box support of FreeBSD is not quite at the level of the others operating systems. Specifically, the guest additions on FreeBSD don't support folder sharing. In the current alpha, the Red GUI is not implemented for FreeBSD. However, I found that there is a simple method to share folders between the macOS host and the FreeBSD guest using NFS. I was able to get it working quickly and reliably, thanks to lionoceros's clear and thorough post on the FreeBSD forums. 

Note: Installing the VirtualBox additions under FreeBSD is straightforward as there is a package available. Be aware that installing the package requires 1GB of disk space. If you plan to install the additions, these instructions should help.

Sunday, 30 April 2017

HTTPS with Lua Sockets

I noticed that a couple of people a week are reading Busted or LuaUnit?. If they were looking for some comparison, they would have been disappointed. Especially as they didn't look at Lua Test Doubles which does give some feedback on Busted and LuaUnit.

I've started out to complete the test-driven development of the stockfetch program using both Busted and LuaUnit. The next step in the project is to read the stock prices from Yahoo. On the surface this didn't seem to be difficult as when I tried GETting a webpage using Lua Socket, it was pretty simple.

But I found that the Lua Socket HTTP "simple" form is unable to handle https. To GET data from an https source you need to use the Lua Socket HTTP "generic" form and the Lua Sec module. Lua Socket HTTP generic form uses LTN12 sinks to collect the content rather than returning a simple string.

Here is a simple example of GETting the content of the Lua Home Page. I hope it is sufficiently self-explanatory.

local https = require('ssl.https')
local ltn12 = require('ltn12')

local responseContent = {}
local returnCode, httpResponseCode, httpHeaders, htttpStatus = https.request{
  url = 'https://www.lua.org',
  sink = ltn12.sink.table(responseContent)

if returnCode then
  print('httpResponseCode: ' .. httpResponseCode)
  print('date: ' .. httpHeaders.date)
  print('server: ' .. httpHeaders.server)
  print('last-modified: ' .. httpHeaders['last-modified'])
  print('content-length: ' .. httpHeaders['content-length'])
  print('content-type: ' .. httpHeaders['content-type'])
  print(httpResponseCode)       -- this will contain a lua socket error message

Note: I used Lua Rocks to install the Lua Sec module. It requires OpenSSL to be installed. If you running Lua under macOS, you might find these instructions helpful. I did. 

Sunday, 12 March 2017

Finding a Hyphenated Sub-String of a String in Lua

The Lua string module has a find function which locates a specified sub-string with a longer string. It seems intuitive that the function looks for a string within a string.

    > str = 'A string containing abc-def amongst other things'
    > =string.find(str, 'amongst')
    29    35

However, what isn't clear from that example that the second argument to Lua's find function is not a simple string but a pattern. A hyper is a "reserved" symbol in a Lua pattern so if you simply search for a string containing one, you will most probably not find it.

    > =string.find(str, 'abc-def')

The '-' character  in a pattern means "Match the previous character (or class) zero or more times, as few times as possible." It can be "escaped" with the '%' character.

    > =string.find(str, 'abc%-def')
    21   27

Alternatively, the find function accepts a fourth parameter which turns off pattern matching and your search will return the expected result. (In order to use it, you must also supply the third parameter which tells the find function where to start its search).

    > =string.find(str, 'abc-def', 1, true)
    21        27

Sunday, 5 March 2017

Lua Error Handling

Like many things in Lua, error handling is simple and straightforward and a little different from many languages. I am writing these simple notes to act as a reminder of those differences.  

There are two functions in Lua that allow you to trap errors, pcall and xpcall. The 'p'  seems to stand for protected, I haven't been able to make a good guess as to the 'x'. The difference between the two is that xpcall allows you to supply your own error handling function.

The main difference is that pcall and xpcall are functions rather than statements. You need to pass the code you wish to protect to them as an argument. You can't just wrap your code in try blocks as you can in many languages. You can't pass code blocks (chunks in Lua terminology) as function arguments in Lua. You need to wrap the code in a function. (It can be anonymous.)

A consequence of this is that you need to remember to pass the function and not the result of the function. A mistake that I found easy to make:
    > function f() return 1 end
    > =pcall(f())
    false attempt to call a number value

It should have been:
    > =pcall(f)
    true 1

You have probably noticed that pcall returns multiple values, the first is a status (true for okay, false if an error occurred) and then either the values returned from your function or from the error function. For example:
    > function fe() error('there was an error') end
    > =pcall(fe)
    false stdin:1: there was an error

You pass arguments to your function by supplying them as additional arguments to pcall:
    function errDemo (i, j) 
      if 'number' ~= type(i) or 'number' ~= type(j) then 
        error{msg='catch this'}
      return i, j

    > =pcall(errDemo, 1, 2)
    true       1 2
    > status, err = pcall(errDemo, "1", 2)
    > =status
    > =err.msg
    catch this

Lastly, xpcall takes an additional function, passed as second argument, that will be called when an error occurs. It is passed object that is returned by the error function. Here is a simple example:
    > function handleError (err) return 'caught you' end
    > =xpcall(errDemo, handleError, "1", 2)
    false caught you