Before:
  Save g:ale_enabled
  Save g:ale_set_signs
  Save g:ale_set_quickfix
  Save g:ale_set_loclist
  Save g:ale_set_highlights
  Save g:ale_echo_cursor
  Save g:ale_buffer_info

  let g:ale_enabled = 0
  let g:ale_set_signs = 0
  let g:ale_set_quickfix = 0
  let g:ale_set_loclist = 0
  let g:ale_set_highlights = 0
  let g:ale_echo_cursor = 0
  let g:expr_list = []

  function EmptyString() abort
    return ''
  endfunction

  runtime autoload/ale/util.vim

  function! ale#util#Execute(expr) abort
    call add(g:expr_list, a:expr)
  endfunction

  call ale#engine#InitBufferInfo(bufnr(''))
  " Call this function first, to clear LSP data.
  call ale#lsp_linter#ClearLSPData()

  call ale#linter#Define('testft', {
  \   'name': 'lsplinter',
  \   'lsp': 'tsserver',
  \   'executable': function('EmptyString'),
  \   'command': function('EmptyString'),
  \   'project_root': function('EmptyString'),
  \   'language': function('EmptyString'),
  \})
  call ale#linter#Define('testft', {
  \   'name': 'lsplinter2',
  \   'lsp': 'tsserver',
  \   'executable': function('EmptyString'),
  \   'command': function('EmptyString'),
  \   'project_root': function('EmptyString'),
  \   'language': function('EmptyString'),
  \})
  call ale#linter#Define('testft', {
  \ 'name': 'otherlinter',
  \ 'callback': 'TestCallback',
  \ 'executable': has('win32') ? 'cmd': 'true',
  \ 'command': 'true',
  \ 'read_buffer': 0,
  \})

After:
  Restore

  delfunction EmptyString
  unlet! g:expr_list
  unlet! b:ale_save_event_fired

  " Clear LSP data after tests.
  call ale#lsp_linter#ClearLSPData()

  runtime autoload/ale/util.vim

  call ale#linter#Reset()

Given testft(Some file with an imaginary filetype):
Execute(ALEStopAllLSPs should clear the loclist):
  " For these tests we only need to set the keys we need.
  let g:ale_buffer_info[bufnr('')].loclist = [
  \ {'linter_name': 'lsplinter'},
  \ {'linter_name': 'otherlinter'},
  \]
  let g:ale_buffer_info[bufnr('')].active_linter_list = [
  \ {'name': 'lsplinter'},
  \ {'name': 'otherlinter'},
  \]

  ALEStopAllLSPs

  " The loclist should be updated.
  AssertEqual
  \ ['otherlinter'],
  \ map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.linter_name')

  " The LSP linter should be removed from the active linter list.
  AssertEqual
  \ ['otherlinter'],
  \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name')

Execute(ALEStopLSP should stop a named LSP):
  let g:ale_buffer_info[bufnr('')].loclist = [
  \ {'linter_name': 'lsplinter'},
  \ {'linter_name': 'lsplinter2'},
  \ {'linter_name': 'otherlinter'},
  \]
  let g:ale_buffer_info[bufnr('')].active_linter_list = [
  \ {'name': 'lsplinter'},
  \ {'name': 'lsplinter2'},
  \ {'name': 'otherlinter'},
  \]
  call ale#lsp_linter#SetLSPLinterMap({
  \ 'conn1': {'name': 'lsplinter'},
  \ 'conn2': {'name': 'lsplinter2'},
  \ 'conn3': {'name': 'lsplinter'},
  \})

  ALEStopLSP lsplinter

  " We should remove only the items for this linter.
  AssertEqual
  \ ['lsplinter2', 'otherlinter'],
  \ map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.linter_name')

  " The linter should be removed from the active linter list.
  AssertEqual
  \ ['lsplinter2', 'otherlinter'],
  \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name')

  " The connections linters with this name should be removed.
  AssertEqual
  \ {'conn2': {'name': 'lsplinter2'}},
  \ ale#lsp_linter#GetLSPLinterMap()

Execute(ALEStopLSP should not clear results for linters not running):
  let g:ale_buffer_info[bufnr('')].loclist = [
  \ {'linter_name': 'lsplinter'},
  \ {'linter_name': 'otherlinter'},
  \]
  let g:ale_buffer_info[bufnr('')].active_linter_list = [
  \ {'name': 'lsplinter'},
  \ {'name': 'otherlinter'},
  \]

  ALEStopLSP lsplinter

  " We should emit a message saying the server isn't running.
  AssertEqual
  \ ['echom ''No running language server with name: lsplinter'''],
  \ g:expr_list

  " We should keep the linter items.
  AssertEqual
  \ ['lsplinter', 'otherlinter'],
  \ map(copy(g:ale_buffer_info[bufnr('')].loclist), 'v:val.linter_name')
  AssertEqual
  \ ['lsplinter', 'otherlinter'],
  \ map(copy(g:ale_buffer_info[bufnr('')].active_linter_list), 'v:val.name')

Execute(ALEStopLSP with a bang should not emit warnings):
  ALEStopLSP! lsplinter

  AssertEqual [], g:expr_list

Execute(ALEStopLSP's completion function should suggest running linter names):
  call ale#lsp_linter#SetLSPLinterMap({
  \ 'conn1': {'name': 'pyright'},
  \ 'conn2': {'name': 'pylsp'},
  \ 'conn3': {'name': 'imaginaryserver'},
  \})

  AssertEqual
  \ ['imaginaryserver', 'pylsp', 'pyright'],
  \ ale#lsp#reset#Complete('', '', 42)
  AssertEqual ['imaginaryserver'], ale#lsp#reset#Complete('inary', '', 42)
  AssertEqual ['pylsp'], ale#lsp#reset#Complete('LSP', '', 42)
