From c2943343107ebccca374d2ae6d7c99dd0589faa5 Mon Sep 17 00:00:00 2001
From: Daniel Hahler <github@thequod.de>
Date: Sat, 21 Jul 2018 22:07:45 +0200
Subject: [PATCH] Coverage reporting via covimerage (#107)

This splits out the tests for cython, since the runtime file gets
reloaded for them, and that resets profiling information.
---
 .circleci/config.yml       | 22 ++++++++++++++--------
 .coveragerc                |  7 +++++++
 .dockerignore              |  2 --
 .gitignore                 |  1 +
 Dockerfile                 | 13 +++++++++----
 Makefile                   | 11 ++++-------
 spec/indent/cython_spec.rb | 33 +++++++++++++++++++++++++++++++++
 spec/indent/indent_spec.rb | 29 -----------------------------
 spec/make-coverage         | 25 +++++++++++++++++++++++++
 spec/spec_helper.rb        | 19 ++++++++++++-------
 spec/vimrc                 | 22 ++++++++++++++++++++++
 11 files changed, 127 insertions(+), 57 deletions(-)
 create mode 100644 .coveragerc
 create mode 100644 spec/indent/cython_spec.rb
 create mode 100755 spec/make-coverage
 create mode 100644 spec/vimrc

diff --git a/.circleci/config.yml b/.circleci/config.yml
index bc0bd36..b9df782 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,27 +1,33 @@
 version: 2
 
+common: &common
+  working_directory: ~/repo
+  docker:
+    - image: blueyed/vim-python-pep8-indent-vims-for-test:2@sha256:a7be5f4d07ed361ce3ca78cedd413d67d583f96ab0a59feb512af89052c50172
+
 jobs:
   test:
-    docker:
-      - image: blueyed/vim-python-pep8-indent-vims-for-test:1@sha256:8c77867e1fdf673a6df0ecf6628f8e4d80579a0a097ec196109ca0bc145d86c0
+    <<: *common
     steps:
       - checkout
       - run:
           name: Run tests
           command: |
-            Xvfb :99 &
-            DISPLAY=:99 VIMRUNNER_REUSE_SERVER=1 rspec spec
+            spec/make-coverage
+      - run:
+          name: Report coverage
+          command: |
+            covimerage xml
+            codecov -X search gcov pycov -f coverage.xml
 
   checkqa:
-    docker:
-      - image: circleci/python:3.7
+    <<: *common
     steps:
       - checkout
       - run:
           name: Lint
           command: |
-            pip install --user vim-vint
-            ~/.local/bin/vint **/*.vim
+            vint **/*.vim
 
 workflows:
   version: 2
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..74cc24e
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,7 @@
+[run]
+plugins = covimerage
+data_file = .coverage_covimerage
+source = indent/python.vim
+
+[report]
+include = indent/python.vim
diff --git a/.dockerignore b/.dockerignore
index 8a03768..1a99a79 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,4 +1,2 @@
 *
 !Gemfile
-!indent
-!spec
diff --git a/.gitignore b/.gitignore
index a01ee28..322fea2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 .*.swp
+.coverage_covimerage
diff --git a/Dockerfile b/Dockerfile
index ce08f9d..85d8e21 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,19 +1,24 @@
 FROM testbed/vim:latest
 
 RUN apk --no-cache add gtk+2.0-dev libx11-dev libxt-dev mcookie xauth xvfb
-RUN install_vim -tag master --with-features=normal \
+# NOTE: +profile needs huge features.
+RUN install_vim -tag master --with-features=huge \
   --disable-channel --disable-netbeans --disable-xim \
   --enable-gui=gtk2 --with-x -build
 RUN ln -s /vim-build/bin/vim-master /usr/bin/gvim
 RUN gvim --version
 
+# Install covimerage and vint.
+# NOTE: we have py2 already via gtk+2.0-dev.
+# NOTE: enum34+pathlib+typing gets installed as workaround for broken vim-vint wheel.
+RUN apk --no-cache add py2-pip \
+  && pip install --no-cache-dir codecov covimerage==0.0.9 vim-vint enum34 pathlib typing \
+  && rm -rf /usr/include /usr/lib/python*/turtle* /usr/lib/python*/tkinter
+
 WORKDIR /vim-python-pep8-indent
 
 ADD Gemfile .
 RUN apk --no-cache add coreutils ruby-bundler
 RUN bundle install
 
-ADD indent ./indent
-ADD spec ./spec
-
 ENTRYPOINT ["rspec", "spec"]
diff --git a/Makefile b/Makefile
index 874c7ed..49d9ade 100644
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,9 @@
 test:
 	VIMRUNNER_REUSE_SERVER=1 xvfb-run bundle exec rspec
 
-test_slow:
-	VIMRUNNER_REUSE_SERVER=0 bundle exec rspec
-
-test_visible:
-	VIMRUNNER_REUSE_SERVER=1 bundle exec rspec
-
 # Run tests in dockerized Vims.
 DOCKER_REPO:=blueyed/vim-python-pep8-indent-vims-for-test
-DOCKER_TAG:=1
+DOCKER_TAG:=2
 DOCKER_IMAGE:=$(DOCKER_REPO):$(DOCKER_TAG)
 
 docker_image:
@@ -26,3 +20,6 @@ test_docker:
 	  docker run --rm -ti -e DISPLAY -e VIMRUNNER_REUSE_SERVER=1 \
 	  -v $(CURDIR):/vim-python-pep8-indent $(DOCKER_IMAGE) $(RSPEC_ARGS) \
 	  $(if $(VIMRUNNER_TEST_DISPLAY),,; ret=$$?; kill $$XVFB_PID; exit $$ret)
+
+test_coverage:
+	spec/make-coverage
diff --git a/spec/indent/cython_spec.rb b/spec/indent/cython_spec.rb
new file mode 100644
index 0000000..6a85790
--- /dev/null
+++ b/spec/indent/cython_spec.rb
@@ -0,0 +1,33 @@
+require "spec_helper"
+
+describe "vim for cython" do
+  before(:all) {
+    vim.command "new"
+    vim.command "set ft=cython"
+    # vim.command("set indentexpr?").should include "GetPythonPEPIndent("
+  }
+  before(:each) {
+    # Insert two blank lines.
+    # The first line is a corner case in this plugin that would shadow the
+    # correct behaviour of other tests. Thus we explicitly jump to the first
+    # line when we require so.
+    vim.feedkeys 'i\<CR>\<CR>\<ESC>'
+  }
+  after(:all) {
+    vim.command "bwipe!"
+  }
+
+  describe "when using a cdef function definition" do
+      it "indents shiftwidth spaces" do
+          vim.feedkeys 'icdef long_function_name(\<CR>arg'
+          indent.should == shiftwidth * 2
+      end
+  end
+
+  describe "when using a cpdef function definition" do
+      it "indents shiftwidth spaces" do
+          vim.feedkeys 'icpdef long_function_name(\<CR>arg'
+          indent.should == shiftwidth * 2
+      end
+  end
+end
diff --git a/spec/indent/indent_spec.rb b/spec/indent/indent_spec.rb
index 871101c..d369c3e 100644
--- a/spec/indent/indent_spec.rb
+++ b/spec/indent/indent_spec.rb
@@ -1,7 +1,6 @@
 require "spec_helper"
 
 shared_examples_for "vim" do
-
   before(:each) {
     # clear buffer
     vim.normal 'gg"_dG'
@@ -573,34 +572,6 @@ describe "vim when using python_pep8_indent_multiline_string=-2" do
   it_behaves_like "multiline strings"
 end
 
-describe "vim for cython" do
-  before {
-    vim.command "enew"
-    vim.command "set ft=cython"
-    vim.command "runtime indent/python.vim"
-
-    # Insert two blank lines.
-    # The first line is a corner case in this plugin that would shadow the
-    # correct behaviour of other tests. Thus we explicitly jump to the first
-    # line when we require so.
-    vim.feedkeys 'i\<CR>\<CR>\<ESC>'
-  }
-
-  describe "when using a cdef function definition" do
-      it "indents shiftwidth spaces" do
-          vim.feedkeys 'icdef long_function_name(\<CR>arg'
-          indent.should == shiftwidth * 2
-      end
-  end
-
-  describe "when using a cpdef function definition" do
-      it "indents shiftwidth spaces" do
-          vim.feedkeys 'icpdef long_function_name(\<CR>arg'
-          indent.should == shiftwidth * 2
-      end
-  end
-end
-
 describe "Handles far away opening parens" do
   before { vim.feedkeys '\<ESC>ggdGifrom foo import (' }
 
diff --git a/spec/make-coverage b/spec/make-coverage
new file mode 100755
index 0000000..4aa981f
--- /dev/null
+++ b/spec/make-coverage
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -ex
+
+rm -f .coverage_covimerage
+export PYTHON_PEP8_INDENT_TEST_PROFILE_BASE=/tmp/vim-python-pep8-profile
+
+Xvfb :99 2>/dev/null >&2 &
+export DISPLAY=:99
+
+export VIMRUNNER_REUSE_SERVER=1
+
+ret=0
+for file in ./spec/indent/*_spec.rb; do
+  # shellcheck disable=SC2086
+  bundle exec rspec "$file" $RSPEC_OPTIONS || ret=1
+
+  for p in "${PYTHON_PEP8_INDENT_TEST_PROFILE_BASE}".*; do
+    cat "$p"
+    covimerage write_coverage --append "$p"
+    rm "$p"
+    covimerage report -m
+  done
+done
+exit $ret
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 221e6ed..40b5bfe 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,5 +1,6 @@
 require 'vimrunner'
 require 'vimrunner/rspec'
+require 'vimrunner/server'
 
 # Explicitly enable usage of "should".
 RSpec.configure do |config|
@@ -13,15 +14,19 @@ Vimrunner::RSpec.configure do |config|
   config.reuse_server = ENV['VIMRUNNER_REUSE_SERVER'] == '1' ? true : false
 
   config.start_vim do
-    vim = config.reuse_server ? Vimrunner.start_gvim : Vimrunner.start
-    plugin_path = File.expand_path('../..', __FILE__)
-
-    # add_plugin appends the path to the rtp... :(
-    # vim.add_plugin(plugin_path, 'indent/python.vim')
+    exe = config.reuse_server ? Vimrunner::Platform.gvim : Vimrunner::Platform.vim
+    vimrc = File.expand_path("../vimrc", __FILE__)
+    vim = Vimrunner::Server.new(:executable => exe,
+                                :vimrc => vimrc).start
+    # More friendly killing.
+    # Otherwise profiling information might not be written.
+    def vim.kill
+      normal(':qall!')
+    end
 
+    plugin_path = File.expand_path('../..', __FILE__)
     vim.command "set rtp^=#{plugin_path}"
-    vim.command "runtime syntax/python.vim"
-    vim.command "runtime indent/python.vim"
+    vim.command "set filetype=python"
 
     def shiftwidth
       @shiftwidth ||= vim.echo("exists('*shiftwidth') ? shiftwidth() : &sw").to_i
diff --git a/spec/vimrc b/spec/vimrc
new file mode 100644
index 0000000..e549f80
--- /dev/null
+++ b/spec/vimrc
@@ -0,0 +1,22 @@
+" vint: -ProhibitSetNoCompatible
+set nocompatible
+
+filetype plugin on
+filetype indent on
+syntax on
+
+set noswapfile nobackup
+
+" remove default ~/.vim directories to avoid loading plugins
+set runtimepath-=~/.vim
+set runtimepath-=~/.vim/after
+
+let sfile = expand('<sfile>')
+let plugin_path = fnamemodify(sfile, ':p:h:h')
+exe 'set runtimepath^='.plugin_path
+
+if !empty($PYTHON_PEP8_INDENT_TEST_PROFILE_BASE)
+  execute printf('profile start %s.%s',
+        \ $PYTHON_PEP8_INDENT_TEST_PROFILE_BASE, getpid())
+  execute 'profile! file '. plugin_path . '/indent/python.vim'
+endif
-- 
2.39.5