Before:
  function! CheckAutocmd(group)
    call ale#events#Init()

    redir => l:output
      execute 'silent! autocmd ' . a:group
    redir END

    let l:matches = []
    let l:header = ''
    " Some event names have aliases, and NeoVim and Vim produce
    " different output. The names are remapped to fix this.
    let l:event_name_corrections = {
    \ 'BufWrite': 'BufWritePre',
    \ 'BufRead': 'BufReadPost',
    \}

    " autocmd commands are split across two lines in output, so we
    " must merge the lines back into one simple line.
    for l:line in split(l:output, "\n")
      if l:line =~# '^ALE' && split(l:line)[0] ==# a:group
        let l:header = split(l:line)[1]
        let l:header = get(l:event_name_corrections, l:header, l:header)
      elseif !empty(l:header)
        " There's an extra line for buffer events, and we should only look
        " for the one matching the current buffer.
        if l:line =~# '<buffer=' . bufnr('') . '>'
          let l:header .= ' <buffer>'
        elseif l:line[:0] is# ' '
          call add(l:matches, join(split(l:header . l:line)))
        else
          let l:header = ''
        endif
      endif
    endfor

    call sort(l:matches)

    return l:matches
  endfunction

  Save g:ale_completion_enabled
  Save g:ale_echo_cursor
  Save g:ale_enabled
  Save g:ale_fix_on_save
  Save g:ale_lint_on_enter
  Save g:ale_lint_on_filetype_changed
  Save g:ale_lint_on_insert_leave
  Save g:ale_lint_on_save
  Save g:ale_lint_on_text_changed
  Save g:ale_pattern_options_enabled
  Save g:ale_hover_cursor
  Save g:ale_close_preview_on_insert

  " Turn everything on by default for these tests.
  let g:ale_completion_enabled = 1
  let g:ale_echo_cursor = 1
  let g:ale_enabled = 1
  let g:ale_fix_on_save = 1
  let g:ale_lint_on_enter = 1
  let g:ale_lint_on_filetype_changed = 1
  let g:ale_lint_on_insert_leave = 1
  let g:ale_lint_on_save = 1
  let g:ale_lint_on_text_changed = 1
  let g:ale_pattern_options_enabled = 1
  let g:ale_hover_cursor = 1
  let g:ale_close_preview_on_insert = 0

After:
  delfunction CheckAutocmd
  Restore

  if g:ale_completion_enabled
    call ale#completion#Enable()
  else
    call ale#completion#Disable()
  endif

  call ale#events#Init()

Execute (All events should be set up when everything is on):
  let g:ale_echo_cursor = 1

  " The InsertEnter event is only added when a mapping is not set.
  AssertEqual
  \ [
  \   'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
  \   'BufReadPost * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
  \   'BufWinEnter * call ale#events#LintOnEnter(str2nr(expand(''<abuf>'')))',
  \   'BufWritePost * call ale#events#SaveEvent(str2nr(expand(''<abuf>'')))',
  \   'CursorHold * if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarningWithDelay() | endif',
  \   'CursorHold if exists(''*ale#lsp#Send'') | call ale#hover#ShowTruncatedMessageAtCursor() | endif',
  \   'CursorMoved * if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarningWithDelay() | endif',
  \   'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))',
  \   'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))',
  \ ] + (
  \   maparg("\<C-c>", 'i') isnot# '<Esc>' && !exists('##ModeChanged')
  \     ? [
  \         'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))',
  \         'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
  \       ]
  \     : []
  \ ) + (
  \   exists('##ModeChanged')
  \     ? ['ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))']
  \     : []
  \ ) + [
  \   'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \   'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \ ],
  \ CheckAutocmd('ALEEvents')

Execute (Only the required events should be bound even if various settings are off):
  let g:ale_enabled = 1
  let g:ale_completion_enabled = 0
  let g:ale_echo_cursor = 0
  let g:ale_fix_on_save = 0
  let g:ale_lint_on_enter = 0
  let g:ale_lint_on_filetype_changed = 0
  let g:ale_lint_on_insert_leave = 0
  let g:ale_lint_on_save = 0
  let g:ale_lint_on_text_changed = 0
  let g:ale_pattern_options_enabled = 0
  let g:ale_hover_cursor = 0

  AssertEqual
  \ [
  \   'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
  \   'BufReadPost * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
  \   'BufWritePost * call ale#events#SaveEvent(str2nr(expand(''<abuf>'')))',
  \ ],
  \ CheckAutocmd('ALEEvents')

Execute (The cursor hover event should be enabled with g:ale_hover_cursor = 1):
  let g:ale_enabled = 1
  let g:ale_completion_enabled = 0
  let g:ale_echo_cursor = 0
  let g:ale_fix_on_save = 0
  let g:ale_lint_on_enter = 0
  let g:ale_lint_on_filetype_changed = 0
  let g:ale_lint_on_insert_leave = 0
  let g:ale_lint_on_save = 0
  let g:ale_lint_on_text_changed = 0
  let g:ale_pattern_options_enabled = 0
  let g:ale_hover_cursor = 1

  AssertEqual
  \ [
  \   'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
  \   'BufReadPost * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
  \   'BufWritePost * call ale#events#SaveEvent(str2nr(expand(''<abuf>'')))',
  \   'CursorHold * if exists(''*ale#lsp#Send'') | call ale#hover#ShowTruncatedMessageAtCursor() | endif',
  \ ],
  \ CheckAutocmd('ALEEvents')

Execute (g:ale_lint_on_text_changed = 1 bind both events):
  let g:ale_lint_on_text_changed = 1

  AssertEqual
  \ [
  \   'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \   'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \ ],
  \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')

Execute (g:ale_lint_on_text_changed = 'always' should bind both events):
  let g:ale_lint_on_text_changed = 'always'

  AssertEqual
  \ [
  \   'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \   'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \ ],
  \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')

Execute (g:ale_lint_on_text_changed = 'normal' should bind only TextChanged):
  let g:ale_lint_on_text_changed = 'normal'

  AssertEqual
  \ [
  \   'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \ ],
  \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')

Execute (g:ale_lint_on_text_changed = 'insert' should bind only TextChangedI):
  let g:ale_lint_on_text_changed = 'insert'

  AssertEqual
  \ [
  \   'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
  \ ],
  \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')

Execute (g:ale_lint_on_insert_leave = 1 should bind InsertLeave or ModeChanged if available):
  let g:ale_lint_on_insert_leave = 1
  let g:ale_echo_cursor = 0

  " CI at least should run this check.
  " There isn't an easy way to save an restore a mapping during running the test.
  if maparg("\<C-c>", 'i') isnot# '<Esc>' && !exists('##ModeChanged')
    AssertEqual
    \ [
    \   'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))',
    \ ],
    \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')
  else
    " If the ModeChanged event is available, starting the timer in InsertEnter is not necessary.
    AssertEqual
    \ [
    \ ],
    \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')
  endif

  if !exists('##ModeChanged')
    " If the ModeChanged event is not available, bind InsertLeave.
    AssertEqual
    \ [
    \   'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
    \ ],
    \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''')
  else
    AssertEqual
    \ [
    \   'ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
    \ ],
    \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^ModeChanged''')
  endif

Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event):
  let g:ale_lint_on_filetype_changed = 1

  AssertEqual
  \ [
  \   'FileType * call ale#events#FileTypeEvent( '
  \     . 'str2nr(expand(''<abuf>'')), '
  \     . 'expand(''<amatch>'')'
  \     . ')',
  \ ],
  \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''\v^FileType''')

Execute (ALECleanupGroup should include the right commands):
  if exists('##VimSuspend')
    AssertEqual [
    \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
    \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
    \ 'VimSuspend * if exists(''*ale#engine#CleanupEveryBuffer'') | call ale#engine#CleanupEveryBuffer() | endif',
    \], CheckAutocmd('ALECleanupGroup')
  else
    AssertEqual [
    \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif',
    \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))',
    \], CheckAutocmd('ALECleanupGroup')
  endif

Execute(ALECompletionActions should always be set up):
  AssertEqual [
  \ 'CompleteDone * call ale#completion#HandleUserData(v:completed_item)',
  \], CheckAutocmd('ALECompletionActions')

Execute(Enabling completion should set up autocmd events correctly):
  let g:ale_completion_enabled = 0
  call ale#completion#Enable()

  AssertEqual [
  \ 'CompleteDone * call ale#completion#Done()',
  \ 'TextChangedI * call ale#completion#Queue()',
  \], CheckAutocmd('ALECompletionGroup')
  AssertEqual 1, g:ale_completion_enabled

Execute(Disabling completion should remove autocmd events correctly):
  let g:ale_completion_enabled = 1
  call ale#completion#Enable()
  call ale#completion#Disable()

  AssertEqual [], CheckAutocmd('ALECompletionGroup')
  AssertEqual 0, g:ale_completion_enabled

Execute(ALE should try to close the preview window on InsertEnter):
  let g:ale_lint_on_insert_leave = 0
  let g:ale_close_preview_on_insert = 1

  AssertEqual
  \ [
  \   'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))',
  \ ],
  \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')
