Home | History | Annotate | Line # | Download | only in unit-tests
check-expect.lua revision 1.3
      1  1.1  rillig #!  /usr/bin/lua
      2  1.3  rillig -- $NetBSD: check-expect.lua,v 1.3 2022/04/15 09:33:20 rillig Exp $
      3  1.1  rillig 
      4  1.1  rillig --[[
      5  1.1  rillig 
      6  1.1  rillig usage: lua ./check-expect.lua *.mk
      7  1.1  rillig 
      8  1.1  rillig Check that each text from an '# expect: ...' comment in the .mk source files
      9  1.1  rillig occurs in the corresponding .exp file, in the same order as in the .mk file.
     10  1.1  rillig 
     11  1.1  rillig Check that each text from an '# expect[+-]offset: ...' comment in the .mk
     12  1.1  rillig source files occurs in the corresponding .exp file and refers back to the
     13  1.1  rillig correct line in the .mk file.
     14  1.1  rillig 
     15  1.1  rillig ]]
     16  1.1  rillig 
     17  1.1  rillig 
     18  1.1  rillig local had_errors = false
     19  1.1  rillig ---@param fmt string
     20  1.1  rillig function print_error(fmt, ...)
     21  1.1  rillig   print(fmt:format(...))
     22  1.1  rillig   had_errors = true
     23  1.1  rillig end
     24  1.1  rillig 
     25  1.1  rillig 
     26  1.1  rillig ---@return nil | string[]
     27  1.1  rillig local function load_lines(fname)
     28  1.1  rillig   local lines = {}
     29  1.1  rillig 
     30  1.1  rillig   local f = io.open(fname, "r")
     31  1.1  rillig   if f == nil then return nil end
     32  1.1  rillig 
     33  1.1  rillig   for line in f:lines() do
     34  1.1  rillig     table.insert(lines, line)
     35  1.1  rillig   end
     36  1.1  rillig   f:close()
     37  1.1  rillig 
     38  1.1  rillig   return lines
     39  1.1  rillig end
     40  1.1  rillig 
     41  1.1  rillig 
     42  1.1  rillig ---@param exp_lines string[]
     43  1.1  rillig local function collect_lineno_diagnostics(exp_lines)
     44  1.1  rillig   ---@type table<string, string[]>
     45  1.1  rillig   local by_location = {}
     46  1.1  rillig 
     47  1.1  rillig   for _, line in ipairs(exp_lines) do
     48  1.1  rillig     ---@type string | nil, string, string
     49  1.1  rillig     local l_fname, l_lineno, l_msg =
     50  1.1  rillig       line:match("^make: \"([^\"]+)\" line (%d+): (.*)")
     51  1.1  rillig     if l_fname ~= nil then
     52  1.1  rillig       local location = ("%s:%d"):format(l_fname, l_lineno)
     53  1.1  rillig       if by_location[location] == nil then
     54  1.1  rillig         by_location[location] = {}
     55  1.1  rillig       end
     56  1.1  rillig       table.insert(by_location[location], l_msg)
     57  1.1  rillig     end
     58  1.1  rillig   end
     59  1.1  rillig 
     60  1.1  rillig   return by_location
     61  1.1  rillig end
     62  1.1  rillig 
     63  1.1  rillig 
     64  1.1  rillig local function check_mk(mk_fname)
     65  1.1  rillig   local exp_fname = mk_fname:gsub("%.mk$", ".exp")
     66  1.1  rillig   local mk_lines = load_lines(mk_fname)
     67  1.1  rillig   local exp_lines = load_lines(exp_fname)
     68  1.1  rillig   if exp_lines == nil then return end
     69  1.1  rillig   local by_location = collect_lineno_diagnostics(exp_lines)
     70  1.1  rillig   local prev_expect_line = 0
     71  1.1  rillig 
     72  1.1  rillig   for mk_lineno, mk_line in ipairs(mk_lines) do
     73  1.1  rillig     for text in mk_line:gmatch("#%s*expect:%s*(.*)") do
     74  1.1  rillig       local i = prev_expect_line
     75  1.3  rillig       -- As of 2022-04-15, some lines in the .exp files contain trailing
     76  1.3  rillig       -- whitespace.  If possible, this should be avoided by rewriting the
     77  1.3  rillig       -- debug logging.  When done, the gsub can be removed.
     78  1.3  rillig       -- See deptgt-phony.exp lines 14 and 15.
     79  1.3  rillig       while i < #exp_lines and text ~= exp_lines[i + 1]:gsub("%s*$", "") do
     80  1.1  rillig         i = i + 1
     81  1.1  rillig       end
     82  1.1  rillig       if i < #exp_lines then
     83  1.1  rillig         prev_expect_line = i + 1
     84  1.1  rillig       else
     85  1.1  rillig         print_error("error: %s:%d: '%s:%d+' must contain '%s'",
     86  1.1  rillig           mk_fname, mk_lineno, exp_fname, prev_expect_line + 1, text)
     87  1.1  rillig       end
     88  1.1  rillig     end
     89  1.2  rillig     if mk_line:match("^#%s*expect%-reset$") then
     90  1.2  rillig       prev_expect_line = 0
     91  1.2  rillig     end
     92  1.1  rillig 
     93  1.1  rillig     ---@param text string
     94  1.1  rillig     for offset, text in mk_line:gmatch("#%s*expect([+%-]%d+):%s*(.*)") do
     95  1.1  rillig       local location = ("%s:%d"):format(mk_fname, mk_lineno + tonumber(offset))
     96  1.1  rillig 
     97  1.1  rillig       local found = false
     98  1.1  rillig       if by_location[location] ~= nil then
     99  1.1  rillig         for i, message in ipairs(by_location[location]) do
    100  1.1  rillig           if message ~= "" and message:find(text, 1, true) then
    101  1.1  rillig             by_location[location][i] = ""
    102  1.1  rillig             found = true
    103  1.1  rillig             break
    104  1.1  rillig           end
    105  1.1  rillig         end
    106  1.1  rillig       end
    107  1.1  rillig 
    108  1.1  rillig       if not found then
    109  1.1  rillig         print_error("error: %s:%d: %s must contain '%s'",
    110  1.1  rillig           mk_fname, mk_lineno, exp_fname, text)
    111  1.1  rillig       end
    112  1.1  rillig     end
    113  1.1  rillig   end
    114  1.1  rillig end
    115  1.1  rillig 
    116  1.1  rillig for _, fname in ipairs(arg) do
    117  1.1  rillig   check_mk(fname)
    118  1.1  rillig end
    119  1.1  rillig os.exit(not had_errors)
    120