From b2d81a8aafb74fdd8447c67977173082990748b6 Mon Sep 17 00:00:00 2001 From: Aleksander Klenov Date: Mon, 25 Nov 2024 18:53:35 +0700 Subject: [PATCH] Untested files are counted taking into account filters include/exclude --- spec/cli_spec.lua | 1 - spec/includeuntestedfiles/2.luacov | 10 +- spec/includeuntestedfiles/3.luacov | 11 +- spec/includeuntestedfiles/bar.lua | 1 + spec/includeuntestedfiles/dir/foo.lua | 77 ++++++++ spec/includeuntestedfiles/dir/moduleA/too.lua | 42 +++++ .../example-src/moduleA/libA.lua | 1 - .../example-src/moduleA/libB.lua | 1 - .../example-src/moduleB/aLib.lua | 1 - .../example-src/moduleB/bLib.lua | 1 - .../example-src/third-module/lib-1.lua | 1 - .../example-src/third-module/lib-2.lua | 1 - spec/includeuntestedfiles/expected.out | 169 +++++++++++++----- spec/includeuntestedfiles/expected2.out | 137 ++++++++++++-- spec/includeuntestedfiles/expected3.out | 20 ++- spec/includeuntestedfiles/subdir/.luacov | 8 - spec/includeuntestedfiles/subdir/expected.out | 44 ----- spec/includeuntestedfiles/subdir/test.lua | 7 - spec/includeuntestedfiles/test.lua | 6 +- spec/util_spec.lua | 80 +++++++++ src/luacov/defaults.lua | 5 +- src/luacov/reporter.lua | 95 ---------- src/luacov/runner.lua | 44 ++--- src/luacov/util.lua | 79 ++++++++ 24 files changed, 582 insertions(+), 260 deletions(-) mode change 100644 => 100755 spec/includeuntestedfiles/2.luacov mode change 100644 => 100755 spec/includeuntestedfiles/3.luacov create mode 100644 spec/includeuntestedfiles/bar.lua create mode 100644 spec/includeuntestedfiles/dir/foo.lua create mode 100644 spec/includeuntestedfiles/dir/moduleA/too.lua delete mode 100755 spec/includeuntestedfiles/example-src/moduleA/libA.lua delete mode 100755 spec/includeuntestedfiles/example-src/moduleA/libB.lua delete mode 100755 spec/includeuntestedfiles/example-src/moduleB/aLib.lua delete mode 100755 spec/includeuntestedfiles/example-src/moduleB/bLib.lua delete mode 100755 spec/includeuntestedfiles/example-src/third-module/lib-1.lua delete mode 100755 spec/includeuntestedfiles/example-src/third-module/lib-2.lua mode change 100755 => 100644 spec/includeuntestedfiles/expected.out delete mode 100644 spec/includeuntestedfiles/subdir/.luacov delete mode 100644 spec/includeuntestedfiles/subdir/expected.out delete mode 100755 spec/includeuntestedfiles/subdir/test.lua mode change 100755 => 100644 spec/includeuntestedfiles/test.lua create mode 100644 spec/util_spec.lua diff --git a/spec/cli_spec.lua b/spec/cli_spec.lua index f771f5a..73df026 100644 --- a/spec/cli_spec.lua +++ b/spec/cli_spec.lua @@ -116,7 +116,6 @@ local function register_cli_tests(enable_cluacov) assert_cli("includeuntestedfiles", enable_cluacov) assert_cli("includeuntestedfiles", enable_cluacov, "expected2.out", "-c 2.luacov") assert_cli("includeuntestedfiles", enable_cluacov, "expected3.out", "-c 3.luacov") - assert_cli("includeuntestedfiles/subdir", enable_cluacov) end) end diff --git a/spec/includeuntestedfiles/2.luacov b/spec/includeuntestedfiles/2.luacov old mode 100644 new mode 100755 index 1394a70..19a1892 --- a/spec/includeuntestedfiles/2.luacov +++ b/spec/includeuntestedfiles/2.luacov @@ -1,9 +1,9 @@ return { - include = { - "example%-src%/moduleA%/*" - }, + -- All files implicitly included + includeuntestedfiles = true, - includeuntestedfiles = { - "example-src/moduleA" + -- In this case, only files from the `dir` directory are included in the calculation. + include = { + "dir%/*" } } diff --git a/spec/includeuntestedfiles/3.luacov b/spec/includeuntestedfiles/3.luacov old mode 100644 new mode 100755 index 9a5507e..82bb8d4 --- a/spec/includeuntestedfiles/3.luacov +++ b/spec/includeuntestedfiles/3.luacov @@ -1,8 +1,9 @@ return { - modules = { - ["libB"] = "example-src/moduleA/libB.lua" - }, - includeuntestedfiles = { - "example-src/moduleA/libB.lua" + -- All files implicitly included + includeuntestedfiles = true, + + -- In this case, files from the `dir` directory are not included in the calculation. + exclude = { + "dir" } } diff --git a/spec/includeuntestedfiles/bar.lua b/spec/includeuntestedfiles/bar.lua new file mode 100644 index 0000000..f2af108 --- /dev/null +++ b/spec/includeuntestedfiles/bar.lua @@ -0,0 +1 @@ +return "This is file Bar" diff --git a/spec/includeuntestedfiles/dir/foo.lua b/spec/includeuntestedfiles/dir/foo.lua new file mode 100644 index 0000000..4698641 --- /dev/null +++ b/spec/includeuntestedfiles/dir/foo.lua @@ -0,0 +1,77 @@ +-- Samurai Name and Wisdom Generator + +-- Function to generate a random samurai name +function generateSamuraiName() + local firstNames = {"Takeda", "Oda", "Tokugawa", "Uesugi", "Shimazu", "Mori", "Date", "Sanada", "Hattori", "Honda"} + local lastNames = {"Nobunaga", "Ieyasu", "Kenshin", "Yoshihiro", "Yoshimoto", "Masamune", "Yukimura", "Hanzo", "Tadakatsu", "Shingen"} + + local firstName = firstNames[math.random(#firstNames)] + local lastName = lastNames[math.random(#lastNames)] + + return firstName .. " " .. lastName +end + +-- Function to generate a random samurai wisdom +function generateSamuraiWisdom() + local wisdoms = { + "The bamboo that bends is stronger than the oak that resists.", + "Victory comes to those who make the last move.", + "Patience is the warrior's greatest weapon.", + "A samurai's mind is as sharp as his blade.", + "In the midst of chaos, there is also opportunity.", + "The journey of a thousand miles begins with a single step.", + "To know oneself is to study oneself in action with another person.", + "The ultimate aim of martial arts is not having to use them.", + "A warrior is worthless unless he rises above others and stands strong in the midst of a storm.", + "The way of the warrior is resolute acceptance of death." + } + + return wisdoms[math.random(#wisdoms)] +end + +-- Function to display ASCII art of a samurai +function displaySamuraiArt() + print(" O") + print(" /|\\") + print(" / | \\") + print(" / | \\") + print(" / | \\") + print(" / | \\") + print(" / | \\") + print(" / | \\") + print("/_______|_______\\") + print(" / \\") + print(" / \\") + print(" / \\") + print(" / \\") + print(" / \\") + print(" / \\") + print(" / \\") + print("/_______________\\") +end + +-- Main function to generate and display samurai name and wisdom +function main() + math.randomseed(os.time()) + + print("Welcome to the Samurai Name and Wisdom Generator!") + print("-----------------------------------------------") + + local samuraiName = generateSamuraiName() + local samuraiWisdom = generateSamuraiWisdom() + + print("\nYour Samurai Name:") + print("------------------") + print(samuraiName) + + print("\nSamurai Wisdom:") + print("---------------") + print(samuraiWisdom) + + print("\nSamurai Art:") + print("------------") + displaySamuraiArt() +end + +-- Run the main function +main() diff --git a/spec/includeuntestedfiles/dir/moduleA/too.lua b/spec/includeuntestedfiles/dir/moduleA/too.lua new file mode 100644 index 0000000..d610117 --- /dev/null +++ b/spec/includeuntestedfiles/dir/moduleA/too.lua @@ -0,0 +1,42 @@ +local max_iterations = 100 +local width = 80 +local height = 40 +local x_min, x_max = -2.0, 1.0 +local y_min, y_max = -1.0, 1.0 + +local function mandelbrot(cx, cy) + local x, y = 0, 0 + local iteration = 0 + + while x*x + y*y <= 4 and iteration < max_iterations do + local x_new = x*x - y*y + cx + y = 2*x*y + cy + x = x_new + iteration = iteration + 1 + end + + return iteration +end + +local function draw_mandelbrot() + for py = 0, height - 1 do + local y = y_min + (y_max - y_min) * py / (height - 1) + local line = "" + + for px = 0, width - 1 do + local x = x_min + (x_max - x_min) * px / (width - 1) + local iteration = mandelbrot(x, y) + + if iteration == max_iterations then + line = line .. "#" + else + local shade = math.floor((iteration / max_iterations) * 10) + line = line .. string.sub(" .:-=+*#%@", shade + 1, shade + 1) + end + end + + print(line) + end +end + +draw_mandelbrot() diff --git a/spec/includeuntestedfiles/example-src/moduleA/libA.lua b/spec/includeuntestedfiles/example-src/moduleA/libA.lua deleted file mode 100755 index eb97ef0..0000000 --- a/spec/includeuntestedfiles/example-src/moduleA/libA.lua +++ /dev/null @@ -1 +0,0 @@ -local a = 1 + 1 diff --git a/spec/includeuntestedfiles/example-src/moduleA/libB.lua b/spec/includeuntestedfiles/example-src/moduleA/libB.lua deleted file mode 100755 index 041dddc..0000000 --- a/spec/includeuntestedfiles/example-src/moduleA/libB.lua +++ /dev/null @@ -1 +0,0 @@ -local b = 1 - math.huge diff --git a/spec/includeuntestedfiles/example-src/moduleB/aLib.lua b/spec/includeuntestedfiles/example-src/moduleB/aLib.lua deleted file mode 100755 index c739c0b..0000000 --- a/spec/includeuntestedfiles/example-src/moduleB/aLib.lua +++ /dev/null @@ -1 +0,0 @@ -local val = "ue" diff --git a/spec/includeuntestedfiles/example-src/moduleB/bLib.lua b/spec/includeuntestedfiles/example-src/moduleB/bLib.lua deleted file mode 100755 index 073617a..0000000 --- a/spec/includeuntestedfiles/example-src/moduleB/bLib.lua +++ /dev/null @@ -1 +0,0 @@ -local test = 123 diff --git a/spec/includeuntestedfiles/example-src/third-module/lib-1.lua b/spec/includeuntestedfiles/example-src/third-module/lib-1.lua deleted file mode 100755 index 00d6bd5..0000000 --- a/spec/includeuntestedfiles/example-src/third-module/lib-1.lua +++ /dev/null @@ -1 +0,0 @@ -return 5 diff --git a/spec/includeuntestedfiles/example-src/third-module/lib-2.lua b/spec/includeuntestedfiles/example-src/third-module/lib-2.lua deleted file mode 100755 index 61c7ebf..0000000 --- a/spec/includeuntestedfiles/example-src/third-module/lib-2.lua +++ /dev/null @@ -1 +0,0 @@ -return 0 diff --git a/spec/includeuntestedfiles/expected.out b/spec/includeuntestedfiles/expected.out old mode 100755 new mode 100644 index 2906ac5..676797e --- a/spec/includeuntestedfiles/expected.out +++ b/spec/includeuntestedfiles/expected.out @@ -1,66 +1,149 @@ ============================================================================== -example-src/moduleA/libA.lua +bar.lua ============================================================================== - 1 local a = 1 + 1 + 1 return "This is file Bar" ============================================================================== -example-src/moduleA/libB.lua +dir/foo.lua ============================================================================== -*0 local b = 1 - math.huge + -- Samurai Name and Wisdom Generator -============================================================================== -example-src/moduleB/aLib.lua -============================================================================== -*0 local val = "ue" + -- Function to generate a random samurai name +*0 function generateSamuraiName() +*0 local firstNames = {"Takeda", "Oda", "Tokugawa", "Uesugi", "Shimazu", "Mori", "Date", "Sanada", "Hattori", "Honda"} +*0 local lastNames = {"Nobunaga", "Ieyasu", "Kenshin", "Yoshihiro", "Yoshimoto", "Masamune", "Yukimura", "Hanzo", "Tadakatsu", "Shingen"} -============================================================================== -example-src/moduleB/bLib.lua -============================================================================== -*0 local test = 123 +*0 local firstName = firstNames[math.random(#firstNames)] +*0 local lastName = lastNames[math.random(#lastNames)] -============================================================================== -example-src/third-module/lib-1.lua -============================================================================== - 1 return 5 +*0 return firstName .. " " .. lastName + end -============================================================================== -example-src/third-module/lib-2.lua -============================================================================== - 1 return 0 + -- Function to generate a random samurai wisdom +*0 function generateSamuraiWisdom() +*0 local wisdoms = { + "The bamboo that bends is stronger than the oak that resists.", + "Victory comes to those who make the last move.", + "Patience is the warrior's greatest weapon.", + "A samurai's mind is as sharp as his blade.", + "In the midst of chaos, there is also opportunity.", + "The journey of a thousand miles begins with a single step.", + "To know oneself is to study oneself in action with another person.", + "The ultimate aim of martial arts is not having to use them.", + "A warrior is worthless unless he rises above others and stands strong in the midst of a storm.", + "The way of the warrior is resolute acceptance of death." + } + +*0 return wisdoms[math.random(#wisdoms)] + end + + -- Function to display ASCII art of a samurai +*0 function displaySamuraiArt() +*0 print(" O") +*0 print(" /|\\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print("/_______|_______\\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print("/_______________\\") + end + + -- Main function to generate and display samurai name and wisdom +*0 function main() +*0 math.randomseed(os.time()) + +*0 print("Welcome to the Samurai Name and Wisdom Generator!") +*0 print("-----------------------------------------------") + +*0 local samuraiName = generateSamuraiName() +*0 local samuraiWisdom = generateSamuraiWisdom() + +*0 print("\nYour Samurai Name:") +*0 print("------------------") +*0 print(samuraiName) + +*0 print("\nSamurai Wisdom:") +*0 print("---------------") +*0 print(samuraiWisdom) + +*0 print("\nSamurai Art:") +*0 print("------------") +*0 displaySamuraiArt() + end + + -- Run the main function +*0 main() ============================================================================== -subdir/test.lua +dir/moduleA/too.lua ============================================================================== +*0 local max_iterations = 100 +*0 local width = 80 +*0 local height = 40 +*0 local x_min, x_max = -2.0, 1.0 +*0 local y_min, y_max = -1.0, 1.0 + + local function mandelbrot(cx, cy) +*0 local x, y = 0, 0 +*0 local iteration = 0 -*0 package.path = package.path .. ";../?.lua" +*0 while x*x + y*y <= 4 and iteration < max_iterations do +*0 local x_new = x*x - y*y + cx +*0 y = 2*x*y + cy +*0 x = x_new +*0 iteration = iteration + 1 + end - -- Don't load some of the modules to prevent them from getting tested/executed - require "example-src.moduleA.libA" - require "example-src.third-module.lib-1" - require "example-src.third-module.lib-2" +*0 return iteration + end + + local function draw_mandelbrot() +*0 for py = 0, height - 1 do +*0 local y = y_min + (y_max - y_min) * py / (height - 1) +*0 local line = "" + +*0 for px = 0, width - 1 do +*0 local x = x_min + (x_max - x_min) * px / (width - 1) +*0 local iteration = mandelbrot(x, y) + +*0 if iteration == max_iterations then +*0 line = line .. "#" + else +*0 local shade = math.floor((iteration / max_iterations) * 10) +*0 line = line .. string.sub(" .:-=+*#%@", shade + 1, shade + 1) + end + end + +*0 print(line) + end + end + +*0 draw_mandelbrot() ============================================================================== test.lua ============================================================================== - - -- Don't load some of the modules to prevent them from getting tested/executed - 1 require "example-src.moduleA.libA" - 1 require "example-src.third-module.lib-1" - 1 require "example-src.third-module.lib-2" + 1 require('bar') ============================================================================== Summary ============================================================================== -File Hits Missed Coverage -------------------------------------------------------- -example-src/moduleA/libA.lua 1 0 100.00% -example-src/moduleA/libB.lua 0 1 0.00% -example-src/moduleB/aLib.lua 0 1 0.00% -example-src/moduleB/bLib.lua 0 1 0.00% -example-src/third-module/lib-1.lua 1 0 100.00% -example-src/third-module/lib-2.lua 1 0 100.00% -subdir/test.lua 0 1 0.00% -test.lua 3 0 100.00% -------------------------------------------------------- -Total 6 4 60.00% +File Hits Missed Coverage +---------------------------------------- +bar.lua 1 0 100.00% +dir/foo.lua 0 43 0.00% +dir/moduleA/too.lua 0 25 0.00% +test.lua 1 0 100.00% +---------------------------------------- +Total 2 68 2.86% diff --git a/spec/includeuntestedfiles/expected2.out b/spec/includeuntestedfiles/expected2.out index e160047..c926529 100644 --- a/spec/includeuntestedfiles/expected2.out +++ b/spec/includeuntestedfiles/expected2.out @@ -1,20 +1,137 @@ ============================================================================== -example-src/moduleA/libA.lua +dir/foo.lua ============================================================================== - 1 local a = 1 + 1 + -- Samurai Name and Wisdom Generator + + -- Function to generate a random samurai name +*0 function generateSamuraiName() +*0 local firstNames = {"Takeda", "Oda", "Tokugawa", "Uesugi", "Shimazu", "Mori", "Date", "Sanada", "Hattori", "Honda"} +*0 local lastNames = {"Nobunaga", "Ieyasu", "Kenshin", "Yoshihiro", "Yoshimoto", "Masamune", "Yukimura", "Hanzo", "Tadakatsu", "Shingen"} + +*0 local firstName = firstNames[math.random(#firstNames)] +*0 local lastName = lastNames[math.random(#lastNames)] + +*0 return firstName .. " " .. lastName + end + + -- Function to generate a random samurai wisdom +*0 function generateSamuraiWisdom() +*0 local wisdoms = { + "The bamboo that bends is stronger than the oak that resists.", + "Victory comes to those who make the last move.", + "Patience is the warrior's greatest weapon.", + "A samurai's mind is as sharp as his blade.", + "In the midst of chaos, there is also opportunity.", + "The journey of a thousand miles begins with a single step.", + "To know oneself is to study oneself in action with another person.", + "The ultimate aim of martial arts is not having to use them.", + "A warrior is worthless unless he rises above others and stands strong in the midst of a storm.", + "The way of the warrior is resolute acceptance of death." + } + +*0 return wisdoms[math.random(#wisdoms)] + end + + -- Function to display ASCII art of a samurai +*0 function displaySamuraiArt() +*0 print(" O") +*0 print(" /|\\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print(" / | \\") +*0 print("/_______|_______\\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print(" / \\") +*0 print("/_______________\\") + end + + -- Main function to generate and display samurai name and wisdom +*0 function main() +*0 math.randomseed(os.time()) + +*0 print("Welcome to the Samurai Name and Wisdom Generator!") +*0 print("-----------------------------------------------") + +*0 local samuraiName = generateSamuraiName() +*0 local samuraiWisdom = generateSamuraiWisdom() + +*0 print("\nYour Samurai Name:") +*0 print("------------------") +*0 print(samuraiName) + +*0 print("\nSamurai Wisdom:") +*0 print("---------------") +*0 print(samuraiWisdom) + +*0 print("\nSamurai Art:") +*0 print("------------") +*0 displaySamuraiArt() + end + + -- Run the main function +*0 main() ============================================================================== -example-src/moduleA/libB.lua +dir/moduleA/too.lua ============================================================================== -*0 local b = 1 - math.huge +*0 local max_iterations = 100 +*0 local width = 80 +*0 local height = 40 +*0 local x_min, x_max = -2.0, 1.0 +*0 local y_min, y_max = -1.0, 1.0 + + local function mandelbrot(cx, cy) +*0 local x, y = 0, 0 +*0 local iteration = 0 + +*0 while x*x + y*y <= 4 and iteration < max_iterations do +*0 local x_new = x*x - y*y + cx +*0 y = 2*x*y + cy +*0 x = x_new +*0 iteration = iteration + 1 + end + +*0 return iteration + end + + local function draw_mandelbrot() +*0 for py = 0, height - 1 do +*0 local y = y_min + (y_max - y_min) * py / (height - 1) +*0 local line = "" + +*0 for px = 0, width - 1 do +*0 local x = x_min + (x_max - x_min) * px / (width - 1) +*0 local iteration = mandelbrot(x, y) + +*0 if iteration == max_iterations then +*0 line = line .. "#" + else +*0 local shade = math.floor((iteration / max_iterations) * 10) +*0 line = line .. string.sub(" .:-=+*#%@", shade + 1, shade + 1) + end + end + +*0 print(line) + end + end + +*0 draw_mandelbrot() ============================================================================== Summary ============================================================================== -File Hits Missed Coverage -------------------------------------------------- -example-src/moduleA/libA.lua 1 0 100.00% -example-src/moduleA/libB.lua 0 1 0.00% -------------------------------------------------- -Total 1 1 50.00% +File Hits Missed Coverage +---------------------------------------- +dir/foo.lua 0 43 0.00% +dir/moduleA/too.lua 0 25 0.00% +---------------------------------------- +Total 0 68 0.00% diff --git a/spec/includeuntestedfiles/expected3.out b/spec/includeuntestedfiles/expected3.out index 5fab67e..58f6b45 100644 --- a/spec/includeuntestedfiles/expected3.out +++ b/spec/includeuntestedfiles/expected3.out @@ -1,14 +1,20 @@ ============================================================================== -example-src/moduleA/libB.lua +bar.lua ============================================================================== -*0 local b = 1 - math.huge + 1 return "This is file Bar" + +============================================================================== +test.lua +============================================================================== + 1 require('bar') ============================================================================== Summary ============================================================================== -File Hits Missed Coverage -------------------------------------------------- -example-src/moduleA/libB.lua 0 1 0.00% -------------------------------------------------- -Total 0 1 0.00% +File Hits Missed Coverage +----------------------------- +bar.lua 1 0 100.00% +test.lua 1 0 100.00% +----------------------------- +Total 2 0 100.00% diff --git a/spec/includeuntestedfiles/subdir/.luacov b/spec/includeuntestedfiles/subdir/.luacov deleted file mode 100644 index e51cce9..0000000 --- a/spec/includeuntestedfiles/subdir/.luacov +++ /dev/null @@ -1,8 +0,0 @@ -return { - include = { - "..%/example%-src/*" - }, - includeuntestedfiles = { - "../example-src" - } -} diff --git a/spec/includeuntestedfiles/subdir/expected.out b/spec/includeuntestedfiles/subdir/expected.out deleted file mode 100644 index f9e3d70..0000000 --- a/spec/includeuntestedfiles/subdir/expected.out +++ /dev/null @@ -1,44 +0,0 @@ -============================================================================== -../example-src/moduleA/libA.lua -============================================================================== - 1 local a = 1 + 1 - -============================================================================== -../example-src/moduleA/libB.lua -============================================================================== -*0 local b = 1 - math.huge - -============================================================================== -../example-src/moduleB/aLib.lua -============================================================================== -*0 local val = "ue" - -============================================================================== -../example-src/moduleB/bLib.lua -============================================================================== -*0 local test = 123 - -============================================================================== -../example-src/third-module/lib-1.lua -============================================================================== - 1 return 5 - -============================================================================== -../example-src/third-module/lib-2.lua -============================================================================== - 1 return 0 - -============================================================================== -Summary -============================================================================== - -File Hits Missed Coverage ----------------------------------------------------------- -../example-src/moduleA/libA.lua 1 0 100.00% -../example-src/moduleA/libB.lua 0 1 0.00% -../example-src/moduleB/aLib.lua 0 1 0.00% -../example-src/moduleB/bLib.lua 0 1 0.00% -../example-src/third-module/lib-1.lua 1 0 100.00% -../example-src/third-module/lib-2.lua 1 0 100.00% ----------------------------------------------------------- -Total 3 3 50.00% diff --git a/spec/includeuntestedfiles/subdir/test.lua b/spec/includeuntestedfiles/subdir/test.lua deleted file mode 100755 index 6e8d60a..0000000 --- a/spec/includeuntestedfiles/subdir/test.lua +++ /dev/null @@ -1,7 +0,0 @@ - -package.path = package.path .. ";../?.lua" - --- Don't load some of the modules to prevent them from getting tested/executed -require "example-src.moduleA.libA" -require "example-src.third-module.lib-1" -require "example-src.third-module.lib-2" diff --git a/spec/includeuntestedfiles/test.lua b/spec/includeuntestedfiles/test.lua old mode 100755 new mode 100644 index 5264f80..eeb4dcf --- a/spec/includeuntestedfiles/test.lua +++ b/spec/includeuntestedfiles/test.lua @@ -1,5 +1 @@ - --- Don't load some of the modules to prevent them from getting tested/executed -require "example-src.moduleA.libA" -require "example-src.third-module.lib-1" -require "example-src.third-module.lib-2" +require('bar') diff --git a/spec/util_spec.lua b/spec/util_spec.lua new file mode 100644 index 0000000..13832d0 --- /dev/null +++ b/spec/util_spec.lua @@ -0,0 +1,80 @@ +local util = require("luacov.util") + +describe("Util", function() + describe("pathjoin", function() + it("smoke", function() + local get_dir_sep_origin = util.get_dir_sep + finally(function() + util.get_dir_sep = get_dir_sep_origin + end) + + util.get_dir_sep = function() + return "-" + end + + local res = util.pathjoin("too", "foo") + assert.equals(res, 'too-foo') + end) + end) + + describe("is_dir", function() + it("is dir", function() + local filename = util.pathjoin(util.get_cur_dir(), "src") + local res = util.is_dir(filename) + assert.truthy(res) + end) + + it("is file", function() + local filename = util.pathjoin(util.get_cur_dir(), "README.md") + local res = util.is_dir(filename) + assert.falsy(res) + end) + end) + + describe("listdir", function() + it("smoke", function() + local path = util.pathjoin(util.get_cur_dir(), "src", "luacov", "reporter") + local res = util.listdir(path) + table.sort(res) + + assert.same(res, {"default.lua", "html", "html.lua"}) + end) + end) + + describe("string_ends_with", function() + it("match at the end", function() + local res = util.string_ends_with("too foo bar", "bar") + assert.truthy(res) + end) + + it("match at the beginning", function() + local res = util.string_ends_with("too foo bar", "too") + assert.falsy(res) + end) + + it("match at the middle", function() + local res = util.string_ends_with("too foo bar", "foo") + assert.falsy(res) + end) + + it("mismatch", function() + local res = util.string_ends_with("too foo bar", "abc") + assert.falsy(res) + end) + + it("search is empty", function() + local res = util.string_ends_with("too foo bar", "") + assert.truthy(res) + end) + + it("empty source", function() + local res = util.string_ends_with("", "hello") + assert.falsy(res) + end) + + it("empty all", function() + local res = util.string_ends_with("", "") + assert.truthy(res) + end) + end) +end) diff --git a/src/luacov/defaults.lua b/src/luacov/defaults.lua index 66d8fd6..5b4b1a9 100644 --- a/src/luacov/defaults.lua +++ b/src/luacov/defaults.lua @@ -67,9 +67,8 @@ return { modules = {}, --- Enable including untested files in report. - -- If `true`, all untested files in "." will be included. - -- If it is a table with directory and file paths, all untested files in these paths will be included. - -- Note that you are not allowed to use patterns in these paths. + -- If `true`, all untested files will be included, according to filters + -- include/exclude. -- Default: false. includeuntestedfiles = false, diff --git a/src/luacov/reporter.lua b/src/luacov/reporter.lua index 0aadce1..4f8b062 100644 --- a/src/luacov/reporter.lua +++ b/src/luacov/reporter.lua @@ -7,7 +7,6 @@ local reporter = {} local LineScanner = require("luacov.linescanner") local luacov = require("luacov.runner") local util = require("luacov.util") -local lfs_ok, lfs = pcall(require, "lfs") ---------------------------------------------------------------- local dir_sep = package.config:sub(1, 1) @@ -15,43 +14,6 @@ if not dir_sep:find("[/\\]") then dir_sep = "/" end - ---- returns all files inside dir ---- @param dir directory to be listed ---- @treturn table with filenames and attributes -local function dirtree(dir) - assert(dir and dir ~= "", "Please pass directory parameter") - if dir:sub(-1):match("[/\\]") then - dir=string.sub(dir, 1, -2) - end - - dir = dir:gsub("[/\\]", dir_sep) - - local function yieldtree(directory) - for entry in lfs.dir(directory) do - if entry ~= "." and entry ~= ".." then - entry=directory..dir_sep..entry - local attr=lfs.attributes(entry) - coroutine.yield(entry,attr) - if attr.mode == "directory" then - yieldtree(entry) - end - end - end - end - - return coroutine.wrap(function() yieldtree(dir) end) -end - ----------------------------------------------------------------- ---- checks if string 'filename' has pattern 'pattern' ---- @param filename ---- @param pattern ---- @return boolean -local function fileMatches(filename, pattern) - return string.find(filename, pattern) -end - ---------------------------------------------------------------- --- Basic reporter class stub. -- Implements 'new', 'run' and 'close' methods required by `report`. @@ -95,63 +57,6 @@ function ReporterBase:new(conf) end end - -- including files without tests - -- only .lua files - if conf.includeuntestedfiles then - if not lfs_ok then - print("The option includeuntestedfiles requires the lfs module (from luafilesystem) to be installed.") - os.exit(1) - end - - local function add_empty_file_coverage_data(file_path) - - -- Leading "./" must be trimmed from the file paths because the paths of tested - -- files do not have a leading "./" either - if (file_path:match("^%.[/\\]")) then - file_path = file_path:sub(3) - end - - if luacov.file_included(file_path) then - local file_stats = { - max = 0, - max_hits = 0 - } - - local filename = luacov.real_name(file_path) - - if not filtered_data[filename] then - table.insert(files, filename) - filtered_data[filename] = file_stats - end - end - - end - - local function add_empty_dir_coverage_data(directory_path) - - for filename, attr in dirtree(directory_path) do - if attr.mode == "file" and fileMatches(filename, '.%.lua$') then - add_empty_file_coverage_data(filename) - end - end - - end - - if (conf.includeuntestedfiles == true) then - add_empty_dir_coverage_data("." .. dir_sep) - - elseif (type(conf.includeuntestedfiles) == "table" and conf.includeuntestedfiles[1]) then - for _, include_path in ipairs(conf.includeuntestedfiles) do - if (fileMatches(include_path, '.%.lua$')) then - add_empty_file_coverage_data(include_path) - else - add_empty_dir_coverage_data(include_path) - end - end - end - - end - table.sort(files) local out, err = io.open(conf.reportfile, "w") diff --git a/src/luacov/runner.lua b/src/luacov/runner.lua index db64f88..edd1655 100644 --- a/src/luacov/runner.lua +++ b/src/luacov/runner.lua @@ -150,13 +150,9 @@ local function on_exit() end end -local dir_sep = package.config:sub(1, 1) +local dir_sep = util.get_dir_sep() local wildcard_expansion = "[^/]+" -if not dir_sep:find("[/\\]") then - dir_sep = "/" -end - local function escape_module_punctuation(ch) if ch == "." then return "/" @@ -305,20 +301,6 @@ local function is_absolute(path) return false end -local function get_cur_dir() - local pwd_cmd = dir_sep == "\\" and "cd 2>nul" or "pwd 2>/dev/null" - local handler = io.popen(pwd_cmd, "r") - local cur_dir = handler:read() - handler:close() - cur_dir = cur_dir:gsub("\r?\n$", "") - - if cur_dir:sub(-1) ~= dir_sep and cur_dir:sub(-1) ~= "/" then - cur_dir = cur_dir .. dir_sep - end - - return cur_dir -end - -- Sets configuration. If some options are missing, default values are used instead. local function set_config(configuration) runner.configuration = {} @@ -339,8 +321,8 @@ local function set_config(configuration) local path = runner.configuration[option] if not is_absolute(path) then - cur_dir = cur_dir or get_cur_dir() - runner.configuration[option] = cur_dir .. path + cur_dir = cur_dir or util.get_cur_dir() + runner.configuration[option] = util.pathjoin(cur_dir, path) end end @@ -458,6 +440,21 @@ function runner.with_luacov(f) end end +-- Recursive search of all lua files +local function find_luas(list_of_lua_modules, path) + local current_dir = util.get_cur_dir() + + for _, filename in ipairs(util.listdir(path)) do + local full_filename = util.pathjoin(path, filename) + if util.is_dir(full_filename) then + find_luas(list_of_lua_modules, full_filename) + elseif util.string_ends_with(full_filename, ".lua") then + local filename_by_pwd = full_filename:sub(#current_dir + 1) + list_of_lua_modules[filename_by_pwd] = {max = 0, max_hits = 0} + end + end +end + -------------------------------------------------- -- Initializes LuaCov runner to start collecting data. -- @param[opt] configuration if string, filename of config file (used to call `load_config`). @@ -507,6 +504,11 @@ function runner.init(configuration) runner.on_exit_trick = on_exit_wrap(on_exit) end + if runner.configuration.includeuntestedfiles then + runner.data = {} + find_luas(runner.data, util.get_cur_dir()) + end + runner.initialized = true runner.paused = false end diff --git a/src/luacov/util.lua b/src/luacov/util.lua index c4a4d3d..5585068 100644 --- a/src/luacov/util.lua +++ b/src/luacov/util.lua @@ -4,6 +4,12 @@ -- @name luacov.util local util = {} +--- Library require +local lfs_ok, lfs = pcall(require, "lfs") +if not lfs_ok then + error("The option includeuntestedfiles requires the lfs module (from luafilesystem) to be installed.") +end + --- Removes a prefix from a string if it's present. -- @param str a string. -- @param prefix a prefix string. @@ -100,4 +106,77 @@ function util.file_exists(name) end end +--- Returns directory path separator +-- @return directory path separator +function util.get_dir_sep() + local dir_sep = package.config:sub(1, 1) + if not dir_sep:find("[/\\]") then + dir_sep = "/" + end + + return dir_sep +end + +--- Returns current directory path +-- @return current directory path +function util.get_cur_dir() + local dir_sep = util.get_dir_sep() + return lfs.currentdir() .. dir_sep +end + +--- Join multiple path components. +-- Concatenates multiple path components into a single path, using the appropriate directory separator. +-- @param first the first path component. +-- @param ... additional path components. +-- @return a single string representing the combined path. +function util.pathjoin(first, ...) + local seconds = {...} + local res = first + local dir_sep = util.get_dir_sep() + + for _, s in ipairs(seconds) do + if util.string_ends_with(res, dir_sep) then + res = res .. s + else + res = res .. dir_sep .. s + end + end + + return res +end + +--- Check if a path is a directory. +-- Determines whether the given path corresponds to a directory. +-- @param path the file system path to check. +-- @return true if the path is a directory, false otherwise. +function util.is_dir(path) + local attr = lfs.attributes(path) + return attr and attr.mode == "directory" +end + +--- List files in a directory. +-- Retrieves a list of filenames in the specified directory, excluding "." and "..". +-- @param path the file system path of the directory to list. +-- @return a table containing the names of the files in the directory. +function util.listdir(path) + local files = {} + + for filename in lfs.dir(path) do + if filename ~= "." and filename ~= ".." then + table.insert(files, filename) + end + end + + return files +end + +--- Check if a string ends with a specified substring. +-- Determines whether the given string ends with the specified ending substring. +-- @param str the string to check. +-- @param ending the substring to look for at the end of the string. +-- @return true if the string ends with the specified substring, false otherwise. +function util.string_ends_with(str, ending) + return ending == "" or str:sub(-#ending) == ending +end + return util