Buildr C0 Coverage Information - RCov

lib/buildr/core/checks.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
lib/buildr/core/checks.rb 253 110
20.16%
26.36%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with this
3 # work for additional information regarding copyright ownership.  The ASF
4 # licenses this file to you under the Apache License, Version 2.0 (the
5 # "License"); you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
13 # License for the specific language governing permissions and limitations under
14 # the License.
15 
16 
17 require 'buildr/core/project'
18 autoload :RSpec, 'rspec'
19 
20 module Buildr
21   # Methods added to Project to allow checking the build.
22   module Checks
23 
24     module Matchers #:nodoc:
25 
26       class << self
27 
28         # Define matchers that operate by calling a method on the tested object.
29         # For example:
30         #   foo.should contain(bar)
31         # calls:
32         #   foo.contain(bar)
33         def match_using(*names)
34           names.each do |name|
35             matcher = Class.new do
36               # Initialize with expected arguments (i.e. contain(bar) initializes with bar).
37               define_method(:initialize) { |*args| @expects = args }
38               # Matches against actual value (i.e. foo.should exist called with foo).
39               define_method(:matches?) do |actual|
40                 @actual = actual
41                 return actual.send("#{name}?", *@expects) if actual.respond_to?("#{name}?")
42                 return actual.send(name, *@expects) if actual.respond_to?(name)
43                 raise "You can't check #{actual}, it doesn't respond to #{name}."
44               end
45               # Some matchers have arguments, others don't, treat appropriately.
46               define_method :failure_message do
47                 args = " " + @expects.map{ |arg| "'#{arg}'" }.join(", ") unless @expects.empty?
48                 "Expected #{@actual} to #{name}#{args}"
49               end
50               define_method :negative_failure_message do
51                 args = " " + @expects.map{ |arg| "'#{arg}'" }.join(", ") unless @expects.empty?
52                 "Expected #{@actual} to not #{name}#{args}"
53               end
54             end
55             # Define method to create matcher.
56             define_method(name) { |*args| matcher.new(*args) }
57           end
58         end
59 
60       end
61 
62       # Define delegate matchers for exist and contain methods.
63       match_using :exist, :contain
64 
65     end
66 
67 
68     # An expectation has subject, description and block. The expectation is validated by running the block,
69     # and can access the subject from the method #it. The description is used for reporting.
70     #
71     # The expectation is run by calling #run_against. You can share expectations by running them against
72     # different projects (or any other context for that matter).
73     #
74     # If the subject is missing, it is set to the argument of #run_against, typically the project itself.
75     # If the description is missing, it is set from the project. If the block is missing, the default behavior
76     # prints "Pending" followed by the description. You can use this to write place holders and fill them later.
77     class Expectation
78 
79       attr_reader :description, :subject, :block
80 
81       # :call-seq:
82       #   initialize(subject, description?) { .... }
83       #   initialize(description?) { .... }
84       #
85       # First argument is subject (returned from it method), second argument is description. If you omit the
86       # description, it will be set from the subject. If you omit the subject, it will be set from the object
87       # passed to run_against.
88       def initialize(*args, &block)
89         @description = args.pop if String === args.last
90         @subject = args.shift
91         raise ArgumentError, "Expecting subject followed by description, and either one is optional. Not quite sure what to do with this list of arguments." unless args.empty?
92         @block = block || lambda { |klass| info "Pending: #{description}" }
93       end
94 
95       # :call-seq:
96       #   run_against(context)
97       #
98       # Runs this expectation against the context object. The context object is different from the subject,
99       # but used as the subject if no subject specified (i.e. returned from the it method).
100       #
101       # This method creates a new context object modeled after the context argument, but a separate object
102       # used strictly for running this expectation, and used only once. The context object will pass methods
103       # to the context argument, so you can call any method, e.g. package(:jar).
104       #
105       # It also adds all matchers defined in Buildr and RSpec, and two additional methods:
106       # * it() -- Returns the subject.
107       # * description() -- Returns the description.
108       def run_against(context)
109         subject = @subject || context
110         description = @description ? "#{subject} #{@description}" : subject.to_s
111         # Define anonymous class and load it with:
112         # - All instance methods defined in context, so we can pass method calls to the context.
113         # - it() method to return subject, description() method to return description.
114         # - All matchers defined by Buildr and RSpec.
115         klass = Class.new
116         klass.instance_eval do
117           context.class.instance_methods.each do |method|
118             define_method(method) { |*args| context.send(method, *args) } unless instance_methods.include?(method)
119           end
120           define_method(:it) { subject }
121           define_method(:description) { description }
122           include ::RSpec::Matchers
123           include Matchers
124         end
125 
126         # Run the expectation. We only print the expectation name when tracing (to know they all ran),
127         # or when we get a failure.
128         begin
129           trace description
130           klass.new.instance_eval &@block
131         rescue Exception=>error
132           raise error.exception("#{description}\n#{error}").tap { |wrapped| wrapped.set_backtrace(error.backtrace) }
133         end
134       end
135 
136     end
137 
138 
139     include Extension
140 
141     before_define(:check => :package) do |project|
142       # The check task can do any sort of interesting things, but the most important is running expectations.
143       project.task("check") do |task|
144         project.expectations.inject(true) do |passed, expect|
145           begin
146             expect.run_against project
147             passed
148           rescue Exception=>ex
149             if verbose
150               error ex
151               error ex.backtrace.select { |line| line =~ /#{Buildr.application.buildfile}/ }.join("\n")
152             end
153             false
154           end
155         end or fail "Checks failed for project #{project.name} (see errors above)."
156       end
157       project.task("package").enhance do |task|
158         # Run all actions before checks.
159         task.enhance { project.task("check").invoke }
160       end
161     end
162 
163 
164     # :call-seq:
165     #    check(description) { ... }
166     #    check(subject, description) { ... }
167     #
168     # Adds an expectation. The expectation is run against the project by the check task, executed after packaging.
169     # You can access any package created by the project.
170     #
171     # An expectation is written using a subject, description and block to validate the expectation. For example:
172     #
173     # For example:
174     #   check package(:jar), "should exist" do
175     #     it.should exist
176     #   end
177     #   check package(:jar), "should contain a manifest" do
178     #     it.should contain("META-INF/MANIFEST.MF")
179     #   end
180     #   check package(:jar).path("com/acme"), "should contain classes" do
181     #     it.should_not be_empty
182     #   end
183     #   check package(:jar).entry("META-INF/MANIFEST"), "should be a recent license" do
184     #     it.should contain(/Copyright (C) 2007/)
185     #   end
186     #
187     # If you omit the subject, the project is used as the subject. If you omit the description, the subject is
188     # used as description.
189     #
190     # During development you can write placeholder expectations by omitting the block. This will simply report
191     # the expectation as pending.
192     def check(*args, &block)
193       expectations << Checks::Expectation.new(*args, &block)
194     end
195 
196     # :call-seq:
197     #   expectations() => Expectation*
198     #
199     # Returns a list of expectations (see #check).
200     def expectations()
201       @expectations ||= []
202     end
203 
204   end
205 
206 end
207 
208 
209 module Rake #:nodoc:
210   class FileTask
211 
212     # :call-seq:
213     #   exist?() => boolean
214     #
215     # Returns true if this file exists.
216     def exist?()
217       File.exist?(name)
218     end
219 
220     # :call-seq:
221     #   empty?() => boolean
222     #
223     # Returns true if file/directory is empty.
224     def empty?()
225       File.directory?(name) ? Dir.glob("#{name}/*").empty? : File.read(name).empty?
226     end
227 
228     # :call-seq:
229     #   contain?(pattern*) => boolean
230     #   contain?(file*) => boolean
231     #
232     # For a file, returns true if the file content matches against all the arguments. An argument may be
233     # a string or regular expression.
234     #
235     # For a directory, return true if the directory contains the specified files. You can use relative
236     # file names and glob patterns (using *, **, etc).
237     def contain?(*patterns)
238       if File.directory?(name)
239         patterns.map { |pattern| "#{name}/#{pattern}" }.all? { |pattern| !Dir[pattern].empty? }
240       else
241         contents = File.read(name)
242         patterns.map { |pattern| Regexp === pattern ? pattern : Regexp.new(Regexp.escape(pattern.to_s)) }.
243           all? { |pattern| contents =~ pattern }
244       end
245     end
246 
247   end
248 end
249 
250 
251 class Buildr::Project
252   include Buildr::Checks
253 end

Generated on 2011-07-06 23:35:37 -0700 with rcov 0.9.8