JanetRossini.github.io

Lua, LSL, Blender, Python in Second Life


Project maintained by JanetRossini

Tests Improvements

Jun 3, 2025 • [luatesting]


We have noticed without surprise that the Tests framework uses some SLua features that are not available in standard Lua. We’d like to be able to use Tests in other environments. While I’m there, I’m going to modify the messages a bit.

I’ll not trouble you with the existing code, this blog is mostly here to document what I’m doing. I’ll probably show some refactoring toward the end of this effort, perhaps today if it goes well.

Yesterday I removed all the backtick messages from the framework, and replaced use of +=, which is not present in standard Lua. Today I plan to edit the messages for consistency, clarity, and simplicity. I’m going to go ahead and create some duplication in the interest of simple changes, and then I’ll look to see if I can improve the code.

Maybe I should call my shots. I propose these messages when tests fail:

assert type message
equals Actual: v1, Expected: v2
nearly equal Actual: v1, Expected v2 within delta
table mismatch Actual table[k] = v1, Expected: v2
table extra Actual table[k] = v, Unexpected key k
error Error: message

If the test-writer (you) provides a custom message, I propose to print that in square brackets after the system message.

Currently, there is a function diagnose:

function Tests:diagnose(result, check_name, expected, message)
   print(self.current_name .. ": ".. tostring(result).. " " .. check_name .. tostring(expected) .."  ".. tostring(message))
end

That’s used just twice:

function Tests:assert_equals(result, expected, message)
   if type(result) == "table" and type(expected) == "table" then
      self:assert_tables_equal(result, expected)
      return
   end
   local message = message or ""
   local correct = result == expected
   if correct then
      tests_passing = tests_passing + 1
   else
      tests_failing = tests_failing + 1
      self:diagnose(result, 'was expected to be ', expected, message)
   end
end

function Tests:assert_nearly_equal(result, expected, delta, message)
   local message = message or ""
   local correct = math.abs(result-expected) <= delta
   if correct then
      tests_passing = tests_passing + 1
   else
      tests_failing = tests_failing + 1
      self:diagnose(result, "should be within " .. tostring(delta) .." of " .. tostring(expected) .. " " ,message)
   end
end

I note that there are quite a few occurrences of the incrementing of the tests_passing and tests_failing members. It would be nice to consolidate that. For now, I think I’ll just generate the correct (!) code for each case and then see about the consolidation. One exception: clearly we need a common function to print our message optionally followed by the user’s message, so I’ll do that.

I’ll just start at the top and work my way down, I guess:

function Tests:assert_equals(result, expected, message)
   if type(result) == "table" and type(expected) == "table" then
      self:assert_tables_equal(result, expected)
      return
   end
   local message = message or ""
   local correct = result == expected
   if correct then
      tests_passing = tests_passing + 1
   else
      tests_failing = tests_failing + 1
      local m = 'Actual: '..tostring(result)..', Expected: '..tostring(expected)..'.'
      self:report(m, message)
   end
end

function Tests:report(diagnostic, message)
   if message ~= '' then
      diagnostic = diagnostic .. ' ['..message..']'
   end
   print(diagnostic)
end

That works as intended, looks OK so far:

Actual: goodbye, Expected: hello. [ key: b]
Actual: oops, Expected: nil. [ unexpected key surprise]
test_sample_ok: 3.9 should be within 0.01 of 4  should fail not close enough  nil
Actual: 3, Expected: 4. [ should fail]
Actual: nil, Expected: hello. [ key: b]
test_exception: raised exception: lua_script:130: attempt to call a nil value
Assertions: Pass 7 Fail 6

Lots of Work Ensues

Current output from the sample tests:

[06:10] Tests: Actual: table[b]=goodbye, Expected: hello in test_result_has_wrong_value
[06:10] Tests: Actual: 3.9, Expected: 4 within 0.01 [should fail] in test_sample_ok
[06:10] Tests: Error: lua_script:151: attempt to call a nil value in test_exception
[06:10] Tests: Actual: 3, Expected: 4. [should fail] in test_sample_fail
[06:10] Tests: Actual: table[b]=nil, Expected: hello in test_result_has_missing_value
[06:10] Tests: Actual: table[surprise]=oops, Unexpected key [surprise] in test_result_has_excess_value
[06:10] Tests: RED: Pass 2 Fail 6 in all Tests.

I am somewhat tired, think I’ll take a break. I’m a bit concerned that I’ve gone too far and made the framework more elaborate than it should be. It needs to be small to be useful in SL. It’s about 100 lines now. I’ll think about it and report further. For now, I’m releasing it.

Safe paths!

Post Script, no pun intended
I’ve cleaned up the code a lot and re-released. Now I need to update the recipe to the current scheme. A Valkyrie’s work is never done, or something.

Safe paths!