coco 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/NEWS ADDED
@@ -0,0 +1,34 @@
1
+ v0.4.1 (2011-02-27)
2
+
3
+ * Quick fix, add forgotten images for html menu
4
+
5
+
6
+ v0.4 (2011-02-26)
7
+
8
+ * add colors to console output (*nix only)
9
+
10
+ * it can exclude unwanted files from the report
11
+
12
+
13
+ v0.3 (2011-02-25)
14
+
15
+ * Report sources not covered at all
16
+
17
+ * Configurable via a simple yaml file
18
+ + threeshold
19
+ + source directories
20
+
21
+ * UTF-8 compliant
22
+
23
+ * Misc
24
+ + sort index.html and console output by percentage
25
+ + display coco's version in index.html
26
+
27
+
28
+ v0.2 (2011-02-24)
29
+
30
+ * Use coco from rspec with a simple require 'coco'
31
+
32
+ * Display filenames covered < 90% on console
33
+
34
+ * Build simple html report only for files covered < 90%
data/README.rdoc ADDED
@@ -0,0 +1,48 @@
1
+ = coco
2
+
3
+ Another COde COverage for ruby 1.9 (from the famous post of Aaron Patterson).
4
+ This one suits my needs.
5
+
6
+ == Features
7
+ * Use it from rspec with a simple <code>require 'coco'</code>
8
+ * Display filenames covered < 90% on console
9
+ * Build <em>simple</em> html report <em>only</em> for files covered < 90%
10
+ * Report sources that have no tests
11
+ * UTF-8 compliant
12
+ * Configuration could be done via a simple yaml file
13
+ * Colorized console output (*nix only)
14
+
15
+ <em>Note: I have tested coco only on debian linux. I have not tested it with the test/unit
16
+ framework.</em>
17
+
18
+ == Documentation
19
+
20
+ require 'coco'
21
+
22
+ at the beginning of your tests, usually in a \*helper\*.rb file.
23
+
24
+ See {the wiki}[https://github.com/lkdjiin/coco/wiki] for more information on using coco.
25
+
26
+ To generate the developper's documentation in YARD format:
27
+ rake doc
28
+
29
+ == Dependencies
30
+
31
+ ruby >= 1.9.2
32
+
33
+ To contribute:
34
+
35
+ * reek
36
+ * rspec
37
+
38
+ == Installing coco
39
+ Download and
40
+ rake install
41
+
42
+ == License
43
+ GPLv3, see COPYING.
44
+
45
+ == Questions and/or Comments
46
+
47
+ Feel free to email {Xavier Nayrac}[mailto:xavier.nayrac@gmail.com]
48
+ with any questions.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'rake'
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Test coco'
7
+ task :default => :spec
8
+
9
+ desc 'Test coco'
10
+ RSpec::Core::RakeTask.new(:spec) do |t|
11
+ t.rspec_opts = ['--color']
12
+ end
13
+
14
+ desc 'Check for code smells'
15
+ task :reek do
16
+ puts 'Checking for code smells...'
17
+ files = Dir.glob 'lib/**/*.rb'
18
+ args = files.join(' ')
19
+ sh "reek --quiet #{args} | ./reek.sed"
20
+ end
21
+
22
+ desc 'Build the gem & install it'
23
+ task :install do
24
+ sh "gem build coco.gemspec"
25
+ f = FileList['coco*gem'].to_a
26
+ sh "gem install #{f.first} --no-rdoc --no-ri"
27
+ end
28
+
29
+ desc 'Generate yard documentation for developpers'
30
+ task :doc do
31
+ exec 'yardoc --title "Coco Documentation" - NEWS COPYING VERSION'
32
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+
2
+ * rubygem
3
+ * quick web site (on GitHub ?)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.1
data/lib/coco.rb ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__)
4
+ $COCO_PATH = File.expand_path(File.expand_path(File.dirname(__FILE__)) + '/..')
5
+ require 'coco/formatter'
6
+ require 'coco/cover'
7
+ require 'coco/writer'
8
+ require 'coco/helpers'
9
+ require 'coco/configuration'
10
+ require 'coco/lister'
11
+ require 'coverage'
12
+
13
+ module Coco
14
+ end
15
+
16
+ Coverage.start
17
+
18
+ at_exit do
19
+ config = Coco::Configuration.new
20
+ result = Coco::CoverageResult.new(config, Coverage.result)
21
+ covered = result.covered_from_domain
22
+
23
+ sources = Coco::SourceLister.new(config).list
24
+ uncovered = Coco::UncoveredLister.new(sources, result.all_from_domain).list
25
+
26
+ puts Coco::ConsoleFormatter.new(covered, uncovered).format
27
+
28
+ html_files = Coco::HtmlFormatter.new(covered).format
29
+ Coco::HtmlFilesWriter.new(html_files).write
30
+
31
+ index = Coco::HtmlIndexFormatter.new(covered, uncovered).format
32
+ Coco::HtmlIndexWriter.new(index).write
33
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'yaml'
4
+
5
+ module Coco
6
+
7
+ # I know the configuration of coco.
8
+ #
9
+ # @example read the threeshold value
10
+ # config = Configuration.new
11
+ # config[:threeshold]
12
+ # => 90
13
+ #
14
+ # You can override the default configuration by putting a '.coco' file
15
+ # in YAML format in the project root directory.
16
+ # @example to override the threeshold put this line in a '.coco' file:
17
+ # :threeshold: 70
18
+ #
19
+ # @note You can set the threeshold above 100% (to be sure to see all files) but you
20
+ # cannot set it under 0.
21
+ class Configuration < Hash
22
+
23
+ def initialize
24
+ self[:threeshold] = 90
25
+ self[:directories] = ['lib']
26
+ self[:excludes] = []
27
+ if File.exist?('.coco')
28
+ conf = YAML.load_file '.coco'
29
+ self.merge!(conf)
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
data/lib/coco/cover.rb ADDED
@@ -0,0 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'coco/cover/coverage_stat'
4
+ require 'coco/cover/coverage_result'
@@ -0,0 +1,48 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Coco
4
+
5
+ # Compute results of interest from the big results information (from Coverage.result)
6
+ class CoverageResult
7
+ # @return [Hash] Coverage for all the sources that live in the root project folder.
8
+ attr_reader :all_from_domain
9
+ # @return [Hash] Coverage for sources that are not sufficiently covered.
10
+ # More technically, the sources that live in the root project folder and for
11
+ # which the coverage percentage is under the threeshold.
12
+ attr_reader :covered_from_domain
13
+
14
+ # @param [Hash] config
15
+ # @param [Hash] raw_results Results obtained from Coverage.result
16
+ def initialize config, raw_results
17
+ @exclude_files = config[:excludes]
18
+ @threeshold = config[:threeshold]
19
+ raise ArgumentError if @threeshold < 0
20
+ @result = raw_results
21
+ exclude_external_sources
22
+ exclude_files_user_dont_want
23
+ exclude_sources_above_threeshold
24
+ end
25
+
26
+ private
27
+
28
+ def exclude_external_sources
29
+ here = Dir.pwd
30
+ @all_from_domain = @result.select {|key, value| key.start_with? here}
31
+ end
32
+
33
+ def exclude_files_user_dont_want
34
+ return if @exclude_files.nil?
35
+ @exclude_files.each do |filename|
36
+ @all_from_domain.delete(File.expand_path(filename))
37
+ end
38
+ end
39
+
40
+ def exclude_sources_above_threeshold
41
+ @covered_from_domain = @all_from_domain.select {|key, value|
42
+ CoverageStat.coverage_percent(value) < @threeshold
43
+ }
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Coco
4
+
5
+ # Give statistics about an array of lines hit.
6
+ #
7
+ # An "array of lines hit" is an array of integers, possibly nil.
8
+ # Such array is obtain from Coverage.result.
9
+ #
10
+ # Each integer represent the state of a source line:
11
+ # * nil: source line will never be reached (like comments)
12
+ # * 0: source line could be reached, but was not
13
+ # * 1 and above: number of time the source line has been reached
14
+ class CoverageStat
15
+
16
+ def CoverageStat.remove_nil_from hits
17
+ hits.select {|elem| not elem.nil?}
18
+ end
19
+
20
+ def CoverageStat.number_of_covered_lines hits
21
+ hits.select {|elem| elem > 0}.size
22
+ end
23
+
24
+ def CoverageStat.coverage_percent hits
25
+ hits = CoverageStat.remove_nil_from hits
26
+ return 0 if hits.empty?
27
+ one_percent = 100.0 / hits.size
28
+ (CoverageStat.number_of_covered_lines(hits) * one_percent).to_i
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,9 @@
1
+ require 'coco/formatter/formatter'
2
+
3
+ require 'coco/formatter/console_formatter'
4
+ require 'coco/formatter/context'
5
+
6
+ require 'coco/formatter/html_formatter'
7
+ require 'coco/formatter/html_index_formatter'
8
+ require 'coco/formatter/template'
9
+ require 'coco/formatter/colored_string'
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Coco
4
+
5
+ # Extend String with ANSI colorization.
6
+ # Do nothing on Windows.
7
+ class ColoredString < String
8
+
9
+ def initialize(str="")
10
+ super(str)
11
+ end
12
+
13
+ def red
14
+ colorize "\033[31m"
15
+ end
16
+
17
+ def yellow
18
+ colorize "\033[33m"
19
+ end
20
+
21
+ private
22
+
23
+ def colorize color_code
24
+ if RUBY_PLATFORM =~ /win32/
25
+ self
26
+ else
27
+ "#{color_code}#{self}\033[0m"
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Coco
4
+
5
+ # I format coverages information for console output
6
+ class ConsoleFormatter < Formatter
7
+
8
+ # return [string] percent covered and associated filenames
9
+ def format
10
+ @formatted_output.join("\n")
11
+ end
12
+
13
+ # @param [Hash] covered
14
+ # @param [Array] uncovered
15
+ def initialize covered, uncovered
16
+ super(covered, uncovered)
17
+ @formatted_output = []
18
+ compute_percentage
19
+ add_percentage_to_uncovered
20
+ @formatted_output.sort!
21
+ @formatted_output.map! do |percentage, filename|
22
+ text = ColoredString.new "#{percentage}% #{filename}"
23
+ if percentage <= 50
24
+ text.red
25
+ else
26
+ text.yellow
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def compute_percentage
34
+ @raw_coverages.each do |filename, coverage|
35
+ percentage = CoverageStat.coverage_percent(coverage)
36
+ @formatted_output << [percentage, filename]
37
+ end
38
+ end
39
+
40
+ def add_percentage_to_uncovered
41
+ @uncovered.each do |filename| @formatted_output << [0, filename] end
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Coco
4
+
5
+ # Contextual information for ERB template, representing each covered files.
6
+ class Context
7
+
8
+ # @param [String] filename Name of the source file
9
+ # @param [Array] lines
10
+ def initialize filename, lines
11
+ @filename = filename
12
+ @lines = lines
13
+ end
14
+
15
+ def get_binding
16
+ binding
17
+ end
18
+ end
19
+
20
+ # Contextual information for ERB template, representing index.html.
21
+ class IndexContext
22
+
23
+ # @todo doc, inheritance (with Context)
24
+ def initialize title, covered, uncovered
25
+ @title = title
26
+ @covered = covered
27
+ @uncovered = uncovered
28
+ end
29
+
30
+ def get_binding
31
+ binding
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Coco
4
+
5
+ # My childs will format coverages information.
6
+ # @abstract
7
+ class Formatter
8
+
9
+ # @param [Hash] raw_coverages The hash from Coverage.result
10
+ # @param [Array] uncovered List on uncovered files
11
+ # @todo I think covered is a better name than raw_coverages
12
+ def initialize raw_coverages, uncovered
13
+ @raw_coverages = raw_coverages
14
+ @uncovered = uncovered
15
+ end
16
+
17
+ def format
18
+ "Implement me in child"
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,39 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'erb'
4
+
5
+ module Coco
6
+
7
+ # I format coverages information into html files.
8
+ # @todo document and change name to HtmlFilesFormatter
9
+ class HtmlFormatter < Formatter
10
+
11
+ def initialize raw_coverages
12
+ super(raw_coverages, [])
13
+ @formatted_output_files = {}
14
+ @context = nil
15
+ @template = Template.open File.join($COCO_PATH,'template/file.erb')
16
+ end
17
+
18
+ def format
19
+ @raw_coverages.each do |filename, coverage|
20
+ build_html filename, coverage
21
+ end
22
+ @formatted_output_files
23
+ end
24
+
25
+ private
26
+
27
+ def build_html filename, coverage
28
+ source = File.readlines filename
29
+ lines = []
30
+ source.each_with_index do |line, index|
31
+ lines << [index+1, line.chomp, coverage[index]]
32
+ end
33
+ @context = Context.new filename, lines
34
+ @formatted_output_files[filename] = @template.result(@context.get_binding)
35
+ end
36
+
37
+ end
38
+
39
+ end