Skip to content

Instantly share code, notes, and snippets.

@ghaberek
Created May 29, 2024 18:52
Show Gist options
  • Save ghaberek/e3d312d3366b047da331283640bef3c5 to your computer and use it in GitHub Desktop.
Save ghaberek/e3d312d3366b047da331283640bef3c5 to your computer and use it in GitHub Desktop.
A simple parser for Euphoria unittest.log files
-- std/utparse.e
include std/io.e
include std/get.e
include std/error.e
include std/pretty.e
include std/sequence.e
include std/types.e
sequence PRETTY_INLINE = PRETTY_DEFAULT
PRETTY_INLINE[DISPLAY_ASCII] = 2
PRETTY_INLINE[LINE_BREAKS] = FALSE
public enum
TEST_PASSED = 1,
TEST_FAILED = 0
public enum
TEST_FILE,
TEST_RESULTS,
TEST_SUMMARY
public enum
RESULT_STATUS,
RESULT_NAME,
RESULT_EXPECTED,
RESULT_OUTCOME,
RESULT_ELAPSED
public enum
SUMMARY_TOTAL,
SUMMARY_FAILED,
SUMMARY_PASSED,
SUMMARY_ELAPSED,
SUMMARY_PERCENT
public function parse_unittest_log(sequence filename)
object content = read_file(filename)
if atom(content) then
return content
end if
-- split the content into sequence of object strings
sequence entries = stdseq:split(content, "entry = ", TRUE)
sequence unittests = {}
for i = 1 to length(entries) do
-- parse the string to an object
object data = stdget:value(entries[i])
-- check the parsing status
if data[1] != GET_SUCCESS then
-- return error? crash?
error:crash("stdget:value() returned %d (i=%d)", {data[1],i})
-- return {}
end if
-- get the actual object
data = data[2]
-- check the first element
switch data[1] do
case "file" then
-- get the file name
sequence file = data[2]
-- add new test to list
unittests = append(unittests, {
file, -- TEST_FILE
{}, -- TEST_RESULTS
{} -- TEST_SUMMARY
})
case "passed" then
-- add placeholder values to result
data = insert(data, 0, 3) -- expected
data = insert(data, 0, 4) -- outcome
-- continue to "failed" entry below
fallthru
case "failed" then
-- get the test values
integer status = equal(data[1],"passed")
sequence name = data[2]
object expected = data[3]
object outcome = data[4]
atom elapsed = data[5]
-- add test result to the list
unittests[$][TEST_RESULTS] &= {{
status, -- RESULT_STATUS
name, -- RESULT_NAME
expected, -- RESULT_EXPECTED
outcome, -- RESULT_OUTCOME
elapsed -- RESULT_ELAPSED
}}
case "summary" then
-- get the summary values
integer total = data[2]
integer failed = data[3]
integer passed = data[4]
atom elapsed = data[5]
atom percent = 0
if total = passed then
percent = 1
elsif total != 0 then
percent = passed / total
end if
percent = percent * 100
-- store the summary in the test
unittests[$][TEST_SUMMARY] = {
total, -- SUMMARY_TOTAL
failed, -- SUMMARY_FAILED
passed, -- SUMMARY_PASSED
elapsed, -- SUMMARY_ELAPSED
percent -- SUMMARY_PERCENT
}
end switch
end for
return unittests
end function
procedure print_unittest_file(integer fn, sequence file)
printf(fn, "%s:\n", {file})
end procedure
procedure print_unittest_result(integer fn, sequence result)
if result[RESULT_STATUS] = TEST_PASSED then
puts(fn, " passed:")
else
puts(fn, " failed:")
end if
printf(fn, " %s", {result[RESULT_NAME]})
if result[RESULT_STATUS] = TEST_FAILED then
puts(fn, ", expected: ")
pretty_print(fn, result[RESULT_EXPECTED], PRETTY_INLINE)
puts(fn, " but got: ")
pretty_print(fn, result[RESULT_OUTCOME], PRETTY_INLINE)
end if
puts(fn, "\n")
end procedure
procedure print_unittest_summary(integer fn, sequence summary)
printf(fn, " %d tests run", {summary[SUMMARY_TOTAL]})
printf(fn, ", %d passed", {summary[SUMMARY_PASSED]})
printf(fn, ", %d failed", {summary[SUMMARY_FAILED]})
printf(fn, ", %d%% success", {summary[SUMMARY_PERCENT]})
puts(fn, "\n")
end procedure
public procedure print_unittest_log(integer fn=1, sequence unittests="unittest.log")
if string(unittests) then
unittests = parse_unittest_log(unittests)
end if
integer total = 0
integer failed = 0
integer passed = 0
atom elapsed = 0
for i = 1 to length(unittests) do
sequence file = unittests[i][TEST_FILE]
sequence results = unittests[i][TEST_RESULTS]
sequence summary = unittests[i][TEST_SUMMARY]
print_unittest_file(fn, file)
for j = 1 to length(results) do
print_unittest_result(fn, results[j])
end for
print_unittest_summary(fn, summary)
total += summary[SUMMARY_TOTAL]
failed += summary[SUMMARY_FAILED]
passed += summary[SUMMARY_PASSED]
elapsed += summary[SUMMARY_ELAPSED]
end for
-- print a total summary if there are multiple files
if length(unittests) > 1 and total != 0 then
atom percent = (passed / total) * 100
print_unittest_file(fn, "summary")
print_unittest_summary(fn, {
total, -- SUMMARY_TOTAL
failed, -- SUMMARY_FAILED
passed, -- SUMMARY_PASSED
elapsed, -- SUMMARY_ELAPSED
percent -- SUMMARY_PERCENT
})
end if
end procedure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment