Include: include/setup.vader Execute (neomake#signs#RedefineErrorSign): Save g:neomake_verbose let g:neomake_verbose = 3 new file file1 let bufnr = bufnr('%') let maker = neomake#utils#MakerFromCommand( \ 'echo file1: E: error without line; echo file1:2: W: warning') call extend(maker, { \ 'name': 'custom_maker', \ 'errorformat': '%E%f:%l: %t: %m,%E%f: %t: %m', \ 'append_file': 0, \ }, 'error') call neomake#Make(1, [maker]) NeomakeTestsWaitForFinishedJobs AssertNeomakeMessage 'Placing sign: sign place 5000 line=2 name=neomake_file_warn buffer='.bufnr('%').'.' AssertNeomakeMessage '\vCould not place signs for 1 entries without line number: \[.*\].', 3 " Test #736. call neomake#signs#RedefineErrorSign({'text': 'X', 'texthl': 'ErrorMsg'}) let sign = substitute(neomake#utils#redir('sign list neomake_file_err'), '\v^[\n]*', '', '') AssertEqual split(sign), ['sign', 'neomake_file_err', 'text=X', 'texthl=ErrorMsg'] AssertEqual neomake#signs#by_lnum(bufnr('%')), {'2': [[5000, 'neomake_file_warn']]} call neomake#Make(1, [maker]) NeomakeTestsWaitForFinishedJobs " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_warn, lnum=2.' AssertNeomakeMessage 'Reused 1 signs.', 3, {'bufnr': bufnr} AssertNeomakeMessage 'Cleaning 0 old signs.', 3, {'bufnr': bufnr} AssertEqual neomake#signs#by_lnum(bufnr('%')), {'2': [[5000, 'neomake_file_warn']]} call neomake#signs#Reset(bufnr, 'file') call neomake#signs#CleanAllOldSigns('file') AssertNeomakeMessage 'Cleaning 1 old signs.', 3 AssertEqual neomake#signs#by_lnum(bufnr), {} bwipe Execute (Placing signs in project mode): new let maker = neomake#utils#MakerFromCommand('echo 1:1: W: warning') call extend(maker, { \ 'name': 'custom_maker', \ 'errorformat': '%E%f:%l: %t: %m', \ }, 'error') file 1 let bufnr = bufnr('%') call neomake#Make(0, [maker]) NeomakeTestsWaitForFinishedJobs AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_project_warn buffer='.bufnr.'.' bd call neomake#signs#Reset(bufnr, 'project') call neomake#signs#CleanAllOldSigns('project') AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} AssertEqual neomake#signs#by_lnum(bufnr), {} exe 'bwipe' bufnr Execute (Signs are not re-used / wiped across modes): new let bufnr = bufnr('%') AssertEqual neomake#signs#by_lnum(bufnr), {} call neomake#signs#PlaceSigns(bufnr('%'), \ [{'type': 'E', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') call neomake#signs#PlaceSigns(bufnr('%'), \ [{'type': 'W', 'bufnr': bufnr('%'), 'lnum': 1}], 'project') AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.bufnr.'.' AssertNeomakeMessage 'Placing sign: sign place 5001 line=1 name=neomake_project_warn buffer='.bufnr.'.' call neomake#signs#ResetProject() AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} call neomake#signs#CleanAllOldSigns('project') AssertNeomakeMessage 'Removing signs: {file: {}, project: {}}.' AssertEqual neomake#signs#by_lnum(bufnr), {'1': [[5000, 'neomake_file_err']]} call neomake#signs#RedefineSign('neomake_file_warn', {}) bwipe Execute (Signs are wiped when buffer gets wiped): new call neomake#signs#PlaceSigns(bufnr('%'), \ [{'type': 'E', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') bwipe " Should not cause 'E158: Invalid buffer name' call neomake#signs#RedefineSign('neomake_file_err', {}) Execute (neomake#signs#by_lnum): new let bufnr = bufnr('%') exe 'sign place 5000 name=neomake_file_err line=1 buffer='.bufnr exe 'sign place 5001 name=neomake_file_warn line=2 buffer='.bufnr exe 'sign place 5002 name=neomake_file_info line=3 buffer='.bufnr AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_info']]} " Visible (last placed sign) is first in list. exe 'sign place 5003 name=neomake_file_info line=1 buffer='.bufnr AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[5003, 'neomake_file_info'], [5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_info']]} bwipe Execute (neomake#signs#by_lnum for invalid bufnr): AssertEqual neomake#signs#by_lnum(9999), {} AssertEqual neomake#signs#by_lnum('9999'), {} Execute (neomake#signs#PlaceSigns): new let bufnr = bufnr('%') let entries = [ \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_info']]} let entries = [ \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_err']]} let entries = [ \ {'lnum': 2, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 4, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 4, 'type': 'I', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_err']], \ '3': [[5002, 'neomake_file_warn']], \ '4': [[5003, 'neomake_file_err']]} call neomake#signs#Reset(bufnr, 'file') call neomake#signs#CleanOldSigns(bufnr, 'file') AssertEqual neomake#signs#by_lnum(bufnr), {} call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr), { \ '2': [[5000, 'neomake_file_err']], \ '3': [[5001, 'neomake_file_warn']], \ '4': [[5002, 'neomake_file_err']]} let entries = [ \ {'lnum': 4, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'I', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr), { \ '2': [[5000, 'neomake_file_err']], \ '3': [[5001, 'neomake_file_warn']], \ '4': [[5002, 'neomake_file_err']]} let entries = [ \ {'lnum': 4, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 5, 'type': 'I', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr), { \ '2': [[5000, 'neomake_file_err']], \ '3': [[5001, 'neomake_file_warn']], \ '4': [[5002, 'neomake_file_err']], \ '5': [[5003, 'neomake_file_info']]} call neomake#signs#Reset(bufnr, 'file') call neomake#signs#CleanOldSigns(bufnr, 'file') AssertEqual neomake#signs#by_lnum(bufnr), {} bwipe Execute (neomake#signs#PlaceSigns with E and I (E after I)): new file foo bwipe Save g:neomake_place_signs_count let g:neomake_place_signs_count = 1 new let bufnr = bufnr('%') let entries = [ \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_err']]} bwipe Execute (neomake#signs#PlaceSigns with E and I (E before I)): Save g:neomake_place_signs_count let g:neomake_place_signs_count = 1 new let bufnr = bufnr('%') let entries = [ \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_err']]} bwipe Execute (neomake#signs#PlaceSigns handles multiple signs per line): Save g:neomake_place_signs_count let g:neomake_place_signs_count = -1 new let bufnr = bufnr('%') let entries = [ \ {'lnum': 1, 'type': 'E', 'bufnr': bufnr}, \ {'lnum': 2, 'type': 'W', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'I', 'bufnr': bufnr}, \ {'lnum': 3, 'type': 'E', 'bufnr': bufnr}] call neomake#signs#PlaceSigns(bufnr, entries, 'file') AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5002, 'neomake_file_err']]} bwipe Execute (Signs get handled across multiple get_list_entries jobs): new let bufnr = bufnr('%') let maker1 = {'_idx': 'maker1'} function! maker1.get_list_entries(jobinfo) abort dict return map(copy(g:neomake_test_entries[self._idx]), \ "extend(v:val, {'bufnr': bufnr('%')}, 'keep')") endfunction let maker2 = copy(maker1) let maker2._idx = 'maker2' let g:neomake_test_entries = { \ 'maker1': [{'type': 'E', 'lnum': 1, 'text': 'error'}], \ 'maker2': [{'type': 'W', 'lnum': 2, 'text': 'warning'}]} call neomake#Make(1, [maker1]) AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']]} call neomake#Make(1, [maker1, maker2]) AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']]} call neomake#Make(1, [maker1]) AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']]} call neomake#Make(1, [maker1, maker2]) AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_warn']]} bwipe Execute (next sign_id based on max): new let bufnr = bufnr('%') exe 'sign place 5002 line=1 name=neomake_file_warn buffer='.bufnr exe 'sign place 5001 line=2 name=neomake_file_warn buffer='.bufnr call neomake#signs#PlaceSigns(bufnr, [{'lnum': 3, 'type': 'W'}], 'file') AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5002, 'neomake_file_warn']], \ '2': [[5001, 'neomake_file_warn']], \ '3': [[5003, 'neomake_file_warn']]} bwipe Execute (file mode signs get placed when job finishes): if NeomakeAsyncTestsSetup() new file signs.test let bufnr = bufnr('%') let options = { \ 'errorformat': '%f:%l:%t:%m', \ 'mapexpr': "bufname('%').':'.v:val"} let maker1 = NeomakeTestsCommandMaker('maker1', 'echo 1:I:msg1; echo 3:W:msg2') call extend(maker1, options) let maker2 = NeomakeTestsCommandMaker('maker2', 'sleep .1; echo 1:W:msg3; echo 2:E:msg4') call extend(maker2, options) call neomake#Make(1, [maker1, maker2]) NeomakeTestsWaitForNextFinishedJob AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_info']], \ '3': [[5001, 'neomake_file_warn']]} NeomakeTestsWaitForFinishedJobs AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_warn']], \ '2': [[5002, 'neomake_file_err']], \ '3': [[5001, 'neomake_file_warn']]} bwipe endif Execute (project mode signs get placed when job finishes): if NeomakeAsyncTestsSetup() new file signs1.test let bufnr1 = bufnr('%') new file signs2.test let bufnr2 = bufnr('%') let maker1 = NeomakeTestsCommandMaker('maker1', \ 'echo signs1.test:1:I:msg1; echo signs2.test:3:W:msg2') let maker1.errorformat = '%f:%l:%t:%m' let maker2 = NeomakeTestsCommandMaker('maker2', \ 'sleep .1; echo signs1.test:1:W:msg3; echo signs2.test:2:E:msg4') let maker2.errorformat = '%f:%l:%t:%m' call neomake#Make(0, [maker1, maker2]) NeomakeTestsWaitForNextFinishedJob AssertEqual neomake#signs#by_lnum(bufnr1), { \ '1': [[5000, 'neomake_project_info']]} AssertEqual neomake#signs#by_lnum(bufnr2), { \ '3': [[5000, 'neomake_project_warn']]} NeomakeTestsWaitForFinishedJobs AssertEqual neomake#signs#by_lnum(bufnr1), { \ '1': [[5000, 'neomake_project_warn']]} AssertEqual neomake#signs#by_lnum(bufnr2), { \ '2': [[5001, 'neomake_project_err']], \ '3': [[5000, 'neomake_project_warn']]} " Verify sign handling with a file mode maker on top. let maker = {'_bufnr': bufnr1} function maker.get_list_entries(...) return [{'bufnr': self._bufnr, 'lnum': 1, 'type': 'E'}] endfunction CallNeomake {'file_mode': 1, 'enabled_makers': [maker]} AssertNeomakeMessage 'Placing sign: sign place 5001 line=1 name=neomake_file_err buffer='.bufnr1.'.' if has('patch-8.1.0384') || has('netbeans_intg') AssertEqual neomake#signs#by_lnum(bufnr1), { \ '1': [[5001, 'neomake_file_err'], [5000, 'neomake_project_warn']]} endif call neomake#signs#ResetFile(bufnr1) call neomake#signs#CleanAllOldSigns('file') AssertEqual neomake#signs#by_lnum(bufnr1), { \ '1': [[5000, 'neomake_project_warn']]} bwipe bwipe endif Execute (Highlights for signs get (re-)defined on ColorScheme event): if exists('g:colors_name') let colorscheme = g:colors_name let had_colorscheme = 1 else let colorscheme = 'default' let had_colorscheme = 0 endif let orig = neomake#utils#redir('hi NeomakeErrorSignDefault') exe 'colorscheme' colorscheme let new = neomake#utils#redir('hi NeomakeErrorSignDefault') if had_colorscheme AssertEqual orig, new else Assert stridx(new, 'cleared') == -1, 'highlight is not cleared.' endif Execute (neomake#signs#PlaceSigns keeps sign moved by lnum): new let bufnr = bufnr('%') function! s:place_sign(lnum) let bufnr = bufnr('%') call neomake#signs#PlaceSigns(bufnr, [ \ {'lnum': a:lnum, 'type': 'E', 'bufnr': bufnr}], 'file') endfunction call s:place_sign(1) AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.bufnr.'.' AssertEqual neomake#signs#by_lnum(bufnr), {'1': [[5000, 'neomake_file_err']]} normal! O AssertEqual neomake#signs#by_lnum(bufnr), {'2': [[5000, 'neomake_file_err']]} call neomake#signs#Reset(bufnr, 'file') call s:place_sign(2) " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=2.' AssertNeomakeMessage 'Reused 1 signs.', 3, {'bufnr': bufnr} call neomake#signs#CleanOldSigns(bufnr, 'file') AssertNeomakeMessage 'Cleaning 0 old signs.', 3, {'bufnr': bufnr} call neomake#signs#Reset(bufnr, 'file') AssertEqual neomake#signs#by_lnum(bufnr), {'2': [[5000, 'neomake_file_err']]} call neomake#signs#CleanOldSigns(bufnr, 'file') AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} AssertEqual neomake#signs#by_lnum(bufnr), {} bwipe! Execute (CleanOldSigns removes unplaced sign from s:placed_signs): new let bufnr = bufnr('%') let s:call_count = 0 let maker = {} function maker.get_list_entries(...) let s:call_count += 1 let bufnr = bufnr('%') let entries = [ \ {'lnum': 1, 'text': '1', 'bufnr': bufnr, 'type': 'E'}, \ ] if s:call_count != 2 let entries += [ \ {'lnum': 2, 'text': '2', 'bufnr': bufnr, 'type': 'E'}, \ ] endif return entries endfunction normal! 3o CallNeomake 1, [maker] AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_err']], \ } CallNeomake 1, [maker] AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ } AssertNeomakeMessage 'Cleaning 1 old signs.', 3, {'bufnr': bufnr} CallNeomake 1, [maker] AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_err']], \ '2': [[5001, 'neomake_file_err']], \ } " AssertNeomakeMessage 'Reusing sign: id=5000, type=neomake_file_err, lnum=1.', 3 AssertNeomakeMessage 'Reused 1 signs.', 3 AssertNeomakeMessage 'Placing sign: sign place 5001 line=2 name=neomake_file_err buffer='.bufnr.'.' bwipe! Execute (neomake#signs#PlaceSigns handles lowercase and fallback entry type): new let bufnr = bufnr('%') call neomake#signs#PlaceSigns(bufnr, [ \ {'type': 'w', 'bufnr': bufnr, 'lnum': 1}, \ {'type': 'i', 'bufnr': bufnr, 'lnum': 2}, \ {'type': 'm', 'bufnr': bufnr, 'lnum': 3}, \ {'type': 'e', 'bufnr': bufnr, 'lnum': 4}, \ {'type': 'x', 'bufnr': bufnr, 'lnum': 5}, \ ], 'file') AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_warn buffer='.bufnr.'.' AssertNeomakeMessage 'Placing sign: sign place 5001 line=2 name=neomake_file_info buffer='.bufnr.'.' AssertNeomakeMessage 'Placing sign: sign place 5002 line=3 name=neomake_file_msg buffer='.bufnr.'.' AssertNeomakeMessage 'Placing sign: sign place 5003 line=4 name=neomake_file_err buffer='.bufnr.'.' AssertNeomakeMessage 'Placing sign: sign place 5004 line=5 name=neomake_file_err buffer='.bufnr.'.' AssertEqual neomake#signs#by_lnum(bufnr), { \ '1': [[5000, 'neomake_file_warn']], \ '2': [[5001, 'neomake_file_info']], \ '3': [[5002, 'neomake_file_msg']], \ '4': [[5003, 'neomake_file_err']], \ '5': [[5004, 'neomake_file_err']], \ } bwipe Execute (Signs should be placed with QuickfixCmdPost already (loclist)): new let s:calls = [] function OnQuickfixCmdPost() call add(s:calls, neomake#signs#by_lnum(bufnr('%'))) endfunction augroup neomake_tests autocmd QuickfixCmdPost laddexpr call OnQuickfixCmdPost() augroup END CallNeomake 1, [g:error_maker] let signs = neomake#signs#by_lnum(bufnr('%')) AssertEqual signs, {'1': [[5000, 'neomake_file_err']]} if has('patch-8.0.1040') " 'efm' in setqflist/getqflist AssertEqual s:calls, [] else AssertEqual s:calls, [signs] endif bwipe delfunction OnQuickfixCmdPost Execute (Signs should be placed with QuickfixCmdPost already (qflist)): new let s:calls = [] function OnQuickfixCmdPost() call add(s:calls, neomake#signs#by_lnum(bufnr('%'))) endfunction augroup neomake_tests autocmd QuickfixCmdPost caddexpr call OnQuickfixCmdPost() augroup END CallNeomake 0, [g:error_maker] let signs = neomake#signs#by_lnum(bufnr('%')) AssertEqual signs, {'1': [[5000, 'neomake_project_err']]} if has('patch-8.0.1040') " 'efm' in setqflist/getqflist AssertEqual s:calls, [] else AssertEqual s:calls, [signs] endif bwipe delfunction OnQuickfixCmdPost Execute (neomake#signs#PlaceSigns: prevents re-used signs from being cleaned): new let bufnr = bufnr('%') call neomake#signs#PlaceSigns(bufnr('%'), \ [{'type': 'E', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') AssertNeomakeMessage 'Placing sign: sign place 5000 line=1 name=neomake_file_err buffer='.bufnr.'.' call neomake#signs#Reset(bufnr, 'file') call neomake#signs#PlaceSigns(bufnr('%'), \ [{'type': 'W', 'bufnr': bufnr('%'), 'lnum': 1}], 'file') AssertNeomakeMessage 'Upgrading sign for lnum=1: sign place 5000 name=neomake_file_warn buffer='.bufnr.'.' call neomake#signs#Reset(bufnr, 'file') AssertNeomakeMessage 'Cleaning 0 old signs.', 3 bwipe Execute (Uses base sign id with only other signs): new sign define testsign exe 'sign place 99 line=1 name=testsign buffer='.bufnr('%') AssertEqual neomake#signs#by_lnum(bufnr('%')), {'1': [[99, 'testsign']]} let maker = {} function! maker.get_list_entries(...) return [{'lnum': 2, 'bufnr': bufnr('%')}] endfunction CallNeomake 1, [maker] AssertEqual neomake#signs#by_lnum(bufnr('%')), { \ '1': [[99, 'testsign']], \ '2': [[5000, 'neomake_file_warn']], \ } sign undefine testsign bwipe!