eetee 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ Gemfile.lock
5
+ coverage/
6
+ doc/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ bundler_args: --without development
2
+ rvm:
3
+ - 1.9.3
4
+ - rbx-19mode
5
+
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+
7
+ group(:test) do
8
+ gem 'mocha', '~> 0.12.0'
9
+
10
+ gem 'simplecov'
11
+ gem 'guard'
12
+ gem 'rb-fsevent'
13
+ gem 'growl'
14
+ end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+
2
+ # parameters:
3
+ # output => the formatted to use
4
+ # backtrace => number of lines, nil = everything
5
+ guard 'eetee', :output => "BetterOutput", :backtrace => nil do
6
+ watch(%r{^lib/eetee/(.+)\.rb$}) { |m| "specs/unit/#{m[1]}_spec.rb" }
7
+ watch(%r{specs/.+\.rb$})
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Julien Ammous
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+
2
+ # Continuous integration ([![Build Status](https://secure.travis-ci.org/schmurfy/eetee.png)](http://travis-ci.org/schmurfy/eetee))
3
+
4
+ This gem is tested against these ruby by travis-ci.org:
5
+
6
+ - MRI 1.9.3
7
+ - rubinius (1.9 mode)
8
+
9
+ # What is this name ?
10
+
11
+ Finding an unused name is getting hard so I finally settled for E.T. because why not ?
12
+ I did not want to hve a gem with a two letters name so here is eetee !
13
+
14
+ # What is this gem ?
15
+
16
+ I used the bacon test framework for quite some time now but I have some issues with it which
17
+ are mostly unfixable without rewriting internals, this is what E.T. is !
18
+ From the outside the specs should run the same on both but the changed internals allow better
19
+ integration with guard amongst other things.
20
+
21
+ My goals were:
22
+ - as light as possible (like bacon)
23
+ - minimal set of helpers, go check rspec if you want more
24
+ - specs file should be executable as is, there is no "eetee" binary
25
+ - specs can be grouped without changing anything in them (run all the spec folder)
26
+ - keep bacon syntax as I am used to it and like it
27
+ - a set of extensions I used often (but not required by default)
28
+
29
+ # Usage
30
+
31
+ E.T. is using itself for its tests, you can look at the spec_helper.rb file and its tests,
32
+ here is a quickstart:
33
+
34
+ create a test file (I suppose you are using bundler, if not you should !):
35
+ ```ruby
36
+ require 'rubygems'
37
+ require 'bundler/setup'
38
+ require "eetee"
39
+
40
+ include EEtee
41
+
42
+ describe 'Tests' do
43
+ before do
44
+ @a = 3
45
+ end
46
+
47
+ should 'have access to instance variables' do
48
+ @a.should == 3
49
+ end
50
+
51
+ should 'wait 1s' do
52
+ sleep 1
53
+ 1.should == 1
54
+ end
55
+
56
+ should 'works 2' do
57
+ (40 + 5).should == 45
58
+ end
59
+
60
+ should 'fails' do
61
+ "toto".should == 4
62
+ end
63
+ end
64
+ ```
65
+
66
+ and to run it:
67
+ ```bash
68
+ $ ruby test.rb
69
+ ```
70
+
71
+ # Available extensions
72
+
73
+ ## guard
74
+ The guard is included inside the gem, just look at the Guardfile for the gem for the syntax (unfortunately guard init excepts the guard to live in a separate gem)
75
+
76
+ ## mocha
77
+ Allow mocha expectations to be considered as E.T. expectations.
78
+
79
+ ## rack
80
+ Boilet plate around rack-test to test rack applications.
81
+
82
+ ## time
83
+ Some time helpers:
84
+ time_block{ ... } => return execution time in milliseconds
85
+ freeze_time => Time.now will return the same time inside the block
86
+
87
+
88
+ # Setting up development environmeent
89
+
90
+ ```bash
91
+ # clone the repository and:
92
+ $ bundle
93
+ $ bundle exec guard
94
+ ```
95
+
96
+ the tests will run when a file changed, if only want to run all tests once:
97
+
98
+ ```bash
99
+ $ bundle exec rake
100
+ ```
101
+
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+
5
+ task :default => :test
6
+
7
+ task :test do
8
+
9
+ # do not generate coverage report under travis
10
+ unless ENV['TRAVIS']
11
+
12
+ require 'simplecov'
13
+ SimpleCov.command_name "E.T."
14
+ SimpleCov.start do
15
+ add_filter ".*_spec"
16
+ add_filter "/helpers/"
17
+ end
18
+ end
19
+
20
+ require 'eetee'
21
+
22
+ runner = EEtee::Runner.new
23
+ runner.run_pattern('specs/**/*_spec.rb')
24
+ runner.report_results()
25
+
26
+ end
27
+
data/eetee.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/eetee/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Julien Ammous"]
6
+ gem.email = ["schmurfy@gmail.com"]
7
+ gem.description = %q{Test framework inspired by Bacon}
8
+ gem.summary = %q{Another test framework}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.name = "eetee"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = EEtee::VERSION
16
+
17
+
18
+ gem.add_dependency 'term-ansicolor', '~> 1.0.7'
19
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module SimpleExtension
3
+ def run(&block)
4
+ super{ run_with_changes(&block) }
5
+ end
6
+
7
+ private
8
+ def run_with_changes(&block)
9
+ Thread.current[:eetee_simple_extension] = [1]
10
+ # puts "I did something before the test"
11
+ block.call
12
+ # puts "and after the test"
13
+ Thread.current[:eetee_simple_extension] << 2
14
+ end
15
+
16
+ end
17
+
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'eetee'
5
+
6
+ require_relative 'extension'
7
+ EEtee::Test.__send__(:include, SimpleExtension)
8
+
9
+ describe 'context' do
10
+ should 'use extension' do
11
+ true.should == true
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require "eetee"
5
+
6
+ include EEtee
7
+
8
+ EEtee.enable_focus_mode = true
9
+
10
+ describe 'Tests' do
11
+ before do
12
+ @a = 3
13
+ end
14
+
15
+ should 'have access to instance variables' do
16
+ @a.should == 3
17
+ end
18
+
19
+ should 'wait 1s' do
20
+ sleep 1
21
+ 1.should == 1
22
+ end
23
+
24
+ should 'works 2', :focus => true do
25
+ (40 + 5).should == 45
26
+ end
27
+
28
+ should 'fails' do
29
+ "toto".should == 4
30
+ end
31
+
32
+ describe 'nested context' do
33
+ should 'also have access to instance variables' do
34
+ @a.should == 3
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require "eetee"
4
+
5
+ include EEtee
6
+
7
+
8
+ shared(:valid_object) do |obj, n|
9
+ should 'receive correct number' do
10
+ n.should == 42
11
+ end
12
+
13
+ should 'respond to :to_i' do
14
+ obj.should.respond_to?(:to_i)
15
+ end
16
+
17
+ describe 'nested' do
18
+ should 'have a length higher than 2' do
19
+ obj.size.should > 2
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ describe 'Tests' do
26
+ before do
27
+ @obj = "string"
28
+ end
29
+
30
+ in_scope do
31
+ run_shared(:valid_object, @obj, 42)
32
+ end
33
+
34
+ end
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require "eetee"
5
+
6
+ include EEtee
7
+
8
+
9
+ describe 'Tests' do
10
+ before do
11
+ @a = 3
12
+ end
13
+
14
+ should 'have access to instance variables' do
15
+ @a.should == 3
16
+ end
17
+
18
+ should 'wait 1s' do
19
+ sleep 1
20
+ 1.should == 1
21
+ end
22
+
23
+ should 'works 2' do
24
+ (40 + 5).should == 45
25
+ end
26
+
27
+ should 'fails' do
28
+ "toto".should == 4
29
+ end
30
+
31
+ describe 'nested context' do
32
+ should 'also have access to instance variables' do
33
+ @a.should == 3
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,107 @@
1
+ module EEtee
2
+
3
+ module Assertions
4
+ def be_a(klass)
5
+ object_class = @object.class
6
+
7
+ invert_helper(
8
+ "expected instance of #{klass}, got #{object_class}",
9
+ "instance of #{klass} not expected"
10
+ ) do
11
+ object_class.should == klass
12
+ end
13
+
14
+ end
15
+
16
+ def raise(error_class = RuntimeError)
17
+ @object.should.be_a ::Proc
18
+
19
+ err = nil
20
+ begin
21
+ self.call()
22
+ rescue => ex
23
+ err = ex
24
+ end
25
+
26
+ invert_helper(
27
+ "expected to raise #{error_class}, got #{err.class}",
28
+ "expected not to raise #{error_class}"
29
+ ) do
30
+ err.class.should == error_class
31
+ end
32
+
33
+ err
34
+ end
35
+
36
+ def close?(target, error_margin)
37
+ invert_helper(
38
+ "expected #{target} += #{error_margin}, got #{target}",
39
+ "expected to be outside of #{target} += #{error_margin}, got #{target}"
40
+ ) do
41
+ (target-error_margin .. target+error_margin).should.include?(@object)
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ class AssertionWrapper < BasicObject
48
+
49
+ instance_methods.each do |name|
50
+ if name =~ /\?|^\W+$/
51
+ undef_method(name)
52
+ end
53
+ end
54
+
55
+ include Assertions
56
+
57
+ def initialize(object)
58
+ @object = object
59
+ @invert = false
60
+ end
61
+
62
+ def method_missing(name, *args, &block)
63
+ ::EEtee.current_test.reporter.increment_assertions()
64
+ ret = @object.__send__(name, *args, &block)
65
+
66
+ if !!ret == !!@invert
67
+ if args.empty?
68
+ msg = "#{@object.inspect}.#{name}() => #{ret}"
69
+ else
70
+ msg = "#{@object.inspect}.#{name}(#{args}) => #{ret}"
71
+ end
72
+
73
+ ::Kernel.raise AssertionFailed.new("#{@invert ? '[not] ' : ''}#{msg}")
74
+ end
75
+ end
76
+
77
+ def not
78
+ @invert = true
79
+ self
80
+ end
81
+
82
+ def be
83
+ self
84
+ end
85
+
86
+ private
87
+ ##
88
+ # invert result if needed.
89
+ def invert_helper(message, invert_message)
90
+ err = nil
91
+
92
+ begin
93
+ ret = yield
94
+ rescue AssertionFailed => ex
95
+ err = ex
96
+ end
97
+
98
+ if err || @invert
99
+ ::Kernel.raise AssertionFailed.new(@invert ? invert_message : message)
100
+ end
101
+
102
+ ret
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,67 @@
1
+ module EEtee
2
+
3
+ module SharedContextMethods
4
+ def before(&block)
5
+ instance_eval(&block)
6
+ end
7
+
8
+ def describe(description, &block)
9
+ vars = {}
10
+
11
+ instance_variables.reject{|name| name.to_s.start_with?('@_') }.each do |name|
12
+ value = instance_variable_get(name)
13
+ vars[name] = value
14
+ end
15
+
16
+ Context.new(description, @_level + 1, @_reporter, vars, @_focus_mode, &block)
17
+ end
18
+
19
+ def should(label, opts = {}, &block)
20
+ it("should #{label}", opts, &block)
21
+ end
22
+
23
+ def it(label, opts = {}, &block)
24
+ if !@_focus_mode || opts[:focus]
25
+ Test.new(label, @_reporter, &block)
26
+ end
27
+ end
28
+ end
29
+
30
+ class Context
31
+ attr_reader :description, :level
32
+
33
+ include SharedContextMethods
34
+
35
+ def description; @_description; end
36
+ def level; @_level; end
37
+
38
+ def initialize(description, level, reporter, vars = {}, focus_mode = false, &block)
39
+ vars.each do |name, value|
40
+ instance_variable_set(name, value)
41
+ end
42
+
43
+ @_focus_mode = focus_mode
44
+
45
+ @_description = description
46
+ @_level = level
47
+ @_reporter = reporter
48
+ @_reporter.around_context(self) do
49
+ run(&block)
50
+ end
51
+ end
52
+
53
+ def run(&block)
54
+ instance_eval(&block)
55
+ end
56
+
57
+ def run_shared(name, *args)
58
+ Shared.run(name, @_reporter, @_level, *args)
59
+ end
60
+
61
+ def in_scope(&block)
62
+ instance_eval(&block)
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,17 @@
1
+ module EEtee
2
+
3
+ class AssertionFailed < RuntimeError
4
+ attr_accessor :test
5
+
6
+ end
7
+
8
+ class Error < RuntimeError
9
+ attr_accessor :error, :test
10
+
11
+ def initialize(error, test)
12
+ @error = error
13
+ @test = test
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,47 @@
1
+ gem 'mocha', '~> 0.12.0'
2
+ require 'mocha_standalone'
3
+
4
+ #
5
+ # This extension ensure that mocha expectations are considered
6
+ # as bacon tests. Amongst other thing it allows to have a test
7
+ # containing only mocha expectations.
8
+ class MochaCounterWrapper
9
+ def initialize(reporter)
10
+ @reporter = reporter
11
+ end
12
+
13
+ def increment
14
+ @reporter.increment_assertions()
15
+ end
16
+ end
17
+
18
+
19
+
20
+ module MochaSpec
21
+ def self.included(klass)
22
+ klass.__send__(:include, Mocha::API)
23
+ end
24
+
25
+ def run(&block)
26
+ super{ run_with_mocha(&block) }
27
+ end
28
+
29
+ private
30
+ def run_with_mocha(&block)
31
+ begin
32
+ mocha_setup
33
+ block.call
34
+ mocha_verify(MochaCounterWrapper.new(@reporter))
35
+ rescue Mocha::ExpectationError => e
36
+ raise EEtee::AssertionFailed.new(e.message)
37
+ # raise EEte::Error.new(:failed, "#{e.message}\n#{e.backtrace[0...10].join("\n")}")
38
+ ensure
39
+ mocha_teardown
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ EEtee::Context.__send__(:include, Mocha::API)
46
+ EEtee::Test.__send__(:include, MochaSpec)
47
+
@@ -0,0 +1,78 @@
1
+
2
+ gem 'rack-test', '~> 0.6.2'
3
+ require 'rack/test'
4
+
5
+ module HTTPTest
6
+ def serve_app(app)
7
+ @app = Rack::Test::Session.new(
8
+ Rack::MockSession.new(app)
9
+ )
10
+ end
11
+
12
+ def request(method, url, opts = {})
13
+ @app.request(url, opts.merge(method: method))
14
+ @app.last_response
15
+ end
16
+
17
+ def propfind(url, properties = :all, opts = {})
18
+ namespaces = {
19
+ 'DAV:' => 'D',
20
+ 'urn:ietf:params:xml:ns:carddav' => 'C',
21
+ 'http://calendarserver.org/ns/' => 'APPLE1'
22
+ }
23
+
24
+ if properties == :all
25
+ body = "<D:allprop />"
26
+
27
+ else
28
+ properties = properties.map do |(name, ns)|
29
+ ns_short = namespaces[ns]
30
+ raise "unknown namespace: #{ns}" unless ns_short
31
+ %.<#{ns_short}:#{name}/>.
32
+ end
33
+
34
+ body = "<D:prop>#{properties.join("\n")}</D:prop>"
35
+ end
36
+
37
+
38
+ data = <<-EOS
39
+ <?xml version="1.0" encoding="UTF-8"?>
40
+ <D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav" xmlns:APPLE1="http://calendarserver.org/ns/">
41
+ #{body}
42
+ </D:propfind>
43
+ EOS
44
+
45
+ request('PROPFIND', url, opts.merge(input: data))
46
+ end
47
+
48
+ def ensure_element_exists(response, expr, namespaces = {'D' => 'DAV:'})
49
+ ret = Nokogiri::XML(response.body)
50
+ ret.css(expr, namespaces).tap{|elements| elements.should.not.be.empty? }
51
+ rescue EEtee::AssertionFailed => err
52
+ raise EEtee::AssertionFailed.new("XML did not match: #{expr}")
53
+ end
54
+
55
+ def ensure_element_does_not_exists(response, expr, namespaces = {})
56
+ ret = Nokogiri::XML(response.body)
57
+ ret.css(expr, namespaces).should.be.empty?
58
+ rescue EEtee::AssertionFailed => err
59
+ raise EEtee::AssertionFailed.new("XML did match: #{expr}")
60
+ end
61
+
62
+ def element_content(response, expr, namespaces = {})
63
+ ret = Nokogiri::XML(response.body)
64
+ elements = ret.css(expr, namespaces)
65
+ if elements.empty?
66
+ :missing
67
+ else
68
+ children = elements.first.element_children
69
+ if children.empty?
70
+ :empty
71
+ else
72
+ children.first.text
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ EEtee::Context.__send__(:include, HTTPTest)
@@ -0,0 +1,25 @@
1
+ module EEteeTimeHelpers
2
+ def time_block
3
+ started_at = Time.now
4
+ yield
5
+ (Time.now - started_at) * 1000
6
+ end
7
+
8
+ # load the mocha extension first to enable
9
+ # this.
10
+ if defined?(MochaCounterWrapper)
11
+ ##
12
+ # Freeze the time, in this block Time.now
13
+ # will always return the same value.
14
+ def freeze_time(t = Time.now)
15
+ Time.stubs(:now).returns(t)
16
+ if block_given?
17
+ yield
18
+ Time.unstub(:now)
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ EEtee::Context.__send__(:include, EEteeTimeHelpers)