diff --git a/.github/workflows/tests-and-coverage.yml b/.github/workflows/tests-and-coverage.yml index 4a4cb29..afd6cf6 100644 --- a/.github/workflows/tests-and-coverage.yml +++ b/.github/workflows/tests-and-coverage.yml @@ -10,21 +10,21 @@ jobs: os: [linux, macos, macos-arm64] lua: [lua=5.1, lua=5.2, lua=5.3, lua=5.4, luajit=@v2.0, luajit=@v2.1] include: - - os: linux - runner: ubuntu-latest - - os: macos - runner: macos-15-intel - - os: macos-arm64 - runner: macos-latest + - os: linux + runner: ubuntu-latest + - os: macos + runner: macos-15-intel + - os: macos-arm64 + runner: macos-latest exclude: - - os: macos-arm64 - lua: luajit=@v2.0 + - os: macos-arm64 + lua: luajit=@v2.0 name: ${{ matrix.os }} (${{ matrix.lua }}) runs-on: ${{ matrix.runner }} steps: # Checks-out the repository under $GITHUB_WORKSPACE. - uses: actions/checkout@v6 - - name: Install libreadline + - name: Install libreadline if: runner.os == 'Linux' run: | sudo apt-get install -y libreadline-dev @@ -43,17 +43,22 @@ jobs: echo lua_install/bin >> $GITHUB_PATH env: MACOSX_DEPLOYMENT_TARGET: 11.0 - + - name: Build tested run: | luarocks make luarocks install luacov-coveralls - - - name: Run tests + + - name: Run tests (sequentially) + continue-on-error: true + run: | + tested -c -n 0 + + - name: Run tests (parallel) continue-on-error: true run: | tested -c - + - name: Save Cache uses: actions/cache/save@v5 with: @@ -73,7 +78,7 @@ jobs: fail-fast: false matrix: lua: [lua=5.1, lua=5.2, lua=5.3, lua=5.4, luajit=@v2.0, luajit=@v2.1] - target: [mingw,vs] + target: [mingw, vs] runs-on: windows-2022 steps: # Checks-out the repository under $GITHUB_WORKSPACE. @@ -90,13 +95,20 @@ jobs: run: | pip install git+https://github.com/luarocks/hererocks hererocks lua_install -r^ --${{ matrix.lua }} --target ${{ matrix.target }} - + - name: Build tested run: | .\lua_install\bin\activate luarocks make luarocks install luacov-coveralls - - name: Run tests + + - name: Run tests (sequentially) + continue-on-error: true + run: | + .\lua_install\bin\activate + tested -c -n 0 + + - name: Run tests (parallel) continue-on-error: true run: | .\lua_install\bin\activate diff --git a/README.md b/README.md index 6147fbf..87c7ba1 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ You can see more tests in this repo's [tests](https://github.com/FourierTransfor - AI was used to help research Lua internals (mostly around file loading and the debug module) - AI helped generate a prettier terminal output. - I fed it my [original terminal output](./docs/original-output.txt), and it re-formatted it to something that looks a lot closer to the final terminal output. +- AI has been used to help debug issues ## Licenses Parts of the following are included in the source code present in this repo: diff --git a/build/tested/libs/ThreadPool.lua b/build/tested/libs/ThreadPool.lua index 5de62c8..34d2013 100644 --- a/build/tested/libs/ThreadPool.lua +++ b/build/tested/libs/ThreadPool.lua @@ -38,6 +38,31 @@ local _unpack = unpack or table.unpack local function worker(num, run_coverage, linda) logger:info("Starting worker %d", num) + + + + + + local tl_ok, tl = pcall(require, "tl") + if tl_ok then + local function tl_fallback_loader(modname) + + local found, fd = tl.search_module(modname, false) + if not found then return end + + local code = fd:read("*all") + fd:close() + local fn, err = tl.load(code, "@" .. found) + if fn then return fn end + return nil, "Error compiling '" .. found .. "': " .. tostring(err) + end + if package.searchers then + table.insert(package.searchers, tl_fallback_loader) + else + table.insert(package.loaders, tl_fallback_loader) + end + end + local luacov if run_coverage then diff --git a/build/tested/test_runner.lua b/build/tested/test_runner.lua index 9642660..534e3b8 100644 --- a/build/tested/test_runner.lua +++ b/build/tested/test_runner.lua @@ -37,6 +37,9 @@ function test_runner.run_tests( + local tl_ok, tl = pcall(require, "tl") + if tl_ok then tl.loader() end + local luacov_loaded, luacov_runner = pcall(require, "luacov.runner") if options and options.coverage and not luacov_loaded then error("Code coverage requires the luacov module to be installed") diff --git a/docs/teal-support.md b/docs/teal-support.md index d37b8c4..63570d5 100644 --- a/docs/teal-support.md +++ b/docs/teal-support.md @@ -32,4 +32,6 @@ Assuming I had multiple unit test files that all pull in `utf8validator`, every For example, if you are doing TDD, you may want to accept the performance loss and use Teal unit test files so that `tested` is _always_ using the Teal files as a source. If you have a large test suite where Lua benchmarking matters, it may make more sense to compile and then test. -In the future, I may consider adding in some way to avoid that additional compilation, so any Teal modules only get compiled once, but it sort've goes against the ethos of unit testing should be isolated if `require`'d modules start being shared across files. \ No newline at end of file +Another thing to keep in mind, if there is a Lua and Teal file in the Lua's instance search path with the same `require`-able name, the Lua file will be pulled in first. + +In the future, I may consider adding in some way to avoid that additional compilation, so any Teal modules only get compiled once, but it sort've goes against the ethos of unit testing (ie: tests should be isolated from one another) if `require`'d modules start being shared across files. diff --git a/src/tested/file_loader.tl b/src/tested/file_loader.tl index a20f349..0a958a2 100644 --- a/src/tested/file_loader.tl +++ b/src/tested/file_loader.tl @@ -37,7 +37,7 @@ end function file_loader.load_and_register_handler(filepath: string) local handler = file_loader.load_file(filepath) as types.FileLoaderHandler - file_loader.register_handler(handler.extension, handler.loader) + file_loader.register_handler(handler.extension, handler.loader) end local tl_ok, tl = pcall(require, "tl") @@ -53,4 +53,4 @@ if tl_ok then file_loader.loader[".tl"] = load_teal_file end -return file_loader \ No newline at end of file +return file_loader diff --git a/src/tested/libs/ThreadPool.tl b/src/tested/libs/ThreadPool.tl index 7e2247b..53c9f37 100644 --- a/src/tested/libs/ThreadPool.tl +++ b/src/tested/libs/ThreadPool.tl @@ -37,7 +37,32 @@ end -- waits for a task, then executes it local function worker(num: integer, run_coverage: boolean, linda: lanes.Linda) logger:info("Starting worker %d", num) - + + -- Unfortunately have to handle this as more of a special case than I was hoping for... + -- To be able to have teal files depend on other teal files, a package loader needs to be added + -- I can't just use tl.load() to handle this here, because it causes the concurrent tests to hang + -- (similar to the luacov problems below). Still not entirely sure why, but appending this loader + -- does appear to solve the issue + local tl_ok, tl = pcall(require, "tl") + if tl_ok then + local function tl_fallback_loader(modname: string): function, string + -- search_all=false: finds only .tl files (not .lua), and respects TL_PATH + local found, fd = tl.search_module(modname, false) + if not found then return end + + local code = fd:read("*all") + fd:close() + local fn, err = tl.load(code, "@" .. found) + if fn then return fn end + return nil, "Error compiling '" .. found .. "': " .. tostring(err) + end + if package.searchers then + table.insert(package.searchers, tl_fallback_loader) + else + table.insert(package.loaders, tl_fallback_loader) + end + end + local luacov: luacov_type if run_coverage then @@ -50,7 +75,7 @@ local function worker(num: integer, run_coverage: boolean, linda: lanes.Linda) luacov_runner.pause() luacov = luacov_runner end - + while true do logger:debug("Worker %d waiting for task", num) -- Get a task from the queue should be a blocking call @@ -63,9 +88,9 @@ local function worker(num: integer, run_coverage: boolean, linda: lanes.Linda) if run_coverage then luacov.pause() end local coverage_data = {} - if run_coverage then - coverage_data = luacov.data - luacov.data = {} + if run_coverage then + coverage_data = luacov.data + luacov.data = {} end if success then @@ -93,9 +118,9 @@ function ThreadPool.init(workers: integer, run_coverage: boolean): ThreadPool end function ThreadPool:map( - func: function(...: any): T, - args_list: {{any}}, - display_func: function(T), + func: function(...: any): T, + args_list: {{any}}, + display_func: function(T), _timeout?: number ): {ThreadPool.Result} @@ -103,7 +128,7 @@ function ThreadPool:map( logger:info("Sending %d tasks", total_calls) for i = 1, total_calls do local task_data = { - order = i, + order = i, func = func, args = args_list[i] } @@ -126,7 +151,7 @@ function ThreadPool:map( return output end end - + end function ThreadPool:shutdown(timeout?: number) diff --git a/src/tested/test_runner.tl b/src/tested/test_runner.tl index 46c7294..9831ff9 100644 --- a/src/tested/test_runner.tl +++ b/src/tested/test_runner.tl @@ -16,9 +16,9 @@ function test_runner.run_with_cleanup(file_loader: types.FileLoader, test_file: assert(type(test_module) == "table" and type(test_module.tests) == "table" and type(test_module.run_only_tests) == "boolean", "It does not appear that '" .. test_file .."' returns the 'tested' module") local test_results = test_module:run(test_file, options) - + logger:info("%s: Clearing out any packages that were loaded", test_file) - for package_name, _ in pairs(package.loaded) do + for package_name, _ in pairs(package.loaded) do if not pre_test_loaded_packages[package_name] then logger:debug("%s: Clearing out package: %s", test_file, package_name) package.loaded[package_name] = nil @@ -37,6 +37,9 @@ function test_runner.run_tests( -- these get called in here to avoid weirdness with lanes -- if they are called outside, the lanes will sometimes hang. + local tl_ok, tl = pcall(require, "tl") + if tl_ok then tl.loader() end + local luacov_loaded, luacov_runner = pcall(require, "luacov.runner") if options and options.coverage and not luacov_loaded then error("Code coverage requires the luacov module to be installed") @@ -71,7 +74,7 @@ function test_runner.run_tests( if options.coverage then luacov_runner.resume() end local test_output = test_runner.run_with_cleanup(file_loader, test_files[i], options) - if options.coverage then + if options.coverage then coverage = luacov_runner.data luacov_runner.resume() end @@ -129,11 +132,11 @@ local function run_parallel_tests( end pool:shutdown() - -- future note: should probably save off the individual coverage results + -- future note: should probably save off the individual coverage results -- before running the combine stats, or do a deep copy or something. -- since the old stats get destroyed during the merge if options.coverage then - + -- mostly code from luacov to help merge stats together. local luacov = require("luacov.runner") luacov.data = {} diff --git a/tests/import_test.tl b/tests/import_test.tl new file mode 100644 index 0000000..b09a44a --- /dev/null +++ b/tests/import_test.tl @@ -0,0 +1,13 @@ +local tested = require("tested") +local str = require("tests.tl_to_import") + +tested.test("imported files should work", function() + tested.assert({ + given = "a nested string", + should = "be equivalent to imported string", + expected = "somewhat nested", + actual = str + }) +end) + +return tested \ No newline at end of file diff --git a/tests/nested_import.tl b/tests/nested_import.tl new file mode 100644 index 0000000..1c401c7 --- /dev/null +++ b/tests/nested_import.tl @@ -0,0 +1 @@ +return "somewhat nested" \ No newline at end of file diff --git a/tests/tl_to_import.tl b/tests/tl_to_import.tl new file mode 100644 index 0000000..44012e6 --- /dev/null +++ b/tests/tl_to_import.tl @@ -0,0 +1,2 @@ +local deeply_nested = require("tests.nested_import") +return deeply_nested \ No newline at end of file