bogus-0.1.6/0000755000004100000410000000000012454377662012705 5ustar www-datawww-databogus-0.1.6/Rakefile0000644000004100000410000000003412454377662014347 0ustar www-datawww-datarequire "bundler/gem_tasks" bogus-0.1.6/Gemfile0000644000004100000410000000013112454377662014173 0ustar www-datawww-datasource "http://rubygems.org" # Specify your gem's dependencies in bogus.gemspec gemspec bogus-0.1.6/pelusa.sh0000755000004100000410000000004112454377662014530 0ustar www-datawww-data#!/bin/bash rvm rbx exec pelusa bogus-0.1.6/features/0000755000004100000410000000000012454377662014523 5ustar www-datawww-databogus-0.1.6/features/step_definitions/0000755000004100000410000000000012454377662020071 5ustar www-datawww-databogus-0.1.6/features/step_definitions/rspec_steps.rb0000644000004100000410000000316412454377662022754 0ustar www-datawww-dataGiven /^a spec file named "([^"]*)" with:$/ do |file_name, string| @spec_file_names ||= [] @spec_file_names << file_name steps %Q{ Given a file named "#{file_name}" with: """ruby require 'bogus/rspec' #{string} """ } end Then /^the specs should fail$/ do steps %Q{ Then the exit status should be 1 } end Then /^the specs should pass$/ do steps %Q{ Then the exit status should be 0 } end When /^I run spec with the following content:$/ do |string| file_name = "foo_#{rand(1000000)}_spec.rb" steps %Q{ Given a spec file named "#{file_name}" with: """ruby #{string} """ } steps %Q{ When I run `rspec #{@spec_file_names.join(' ')}` } end Then /^spec file with following content should pass:$/ do |string| steps %Q{ When I run spec with the following content: """ruby #{string} """ Then the specs should pass } end Then /^spec file with following content should fail:$/ do |string| steps %Q{ When I run spec with the following content: """ruby #{string} """ Then the specs should fail } end Then /^the following test should pass:$/ do |string| steps %Q{ When I run spec with the following content: """ruby describe Bogus do specify do #{string} end end """ Then the specs should pass } end Then /^minitest file "([^"]*)" with the following content should (pass|fail):$/ do |file_name, pass_fail, string| steps %Q{ Given a file named "#{file_name}" with: """ruby #{string} """ When I run `ruby #{file_name}` Then the specs should #{pass_fail} } end bogus-0.1.6/features/license.md0000644000004100000410000000210012454377662016460 0ustar www-datawww-data# The MIT License (MIT) Copyright (c) 2012-2013 Adam Pohorecki Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bogus-0.1.6/features/readme.md0000644000004100000410000001612412454377662016306 0ustar www-datawww-dataBogus is a library that aims to reduce the risks associated with isolated unit testing. ## The problem It is not uncommon to encounter code like this in isolated unit tests: it "returns the average score" do scores = stub(get: [5, 9]) students = stub(all: ["John", "Mary"]) report_card = ReportCard.new(scores, students) expect(report_card.average_score).to eq(7) end _NOTE: In the above example we use mocha syntax, but this patten is common to all the major mocking frameworks_ The test above not only ensures that `ReportCard` can calculate the average score for all the students, but it also specifies how this class will interact with its collaborators and what those collaborators will be. This style of testing enables us to practice so called *programming by wishful thinking*. We can implement `ReportCard` and get it to work before it's collaborators are implemented. This way we can design our system top-down and only implement what we need. This is a Very Good Thing(tm). However, the same freedom that comes from not having to implement the collaborators, can quickly turn against us. Once implement `ReportCard`, what test will tell us that `Scores` and `Students` are not implemented yet? The kind of stubbing that you see in the example above requires us to write integrated or end-to-end test *just to make sure that the objects we implemented fit together*. This is a problem, because those tests can be quite slow and hard to set up in a way that covers all the integration points between our objects. Another problem is that it's quite likely that `Students` and `Scores` will be collaborating with more objects than the `ReportCard`. If so, you will find yourself typing code like this over and over again: students = stub(all: ["John", "Mary"]) This is duplication. It is also a problem, because if you decide to change the interface of the `Students` class, suddenly you will have to remember every place you created that stub and fix it. Your tests won't help you, because they don't have any idea what the `Students` interface should look like. ## The solution Bogus makes your test doubles more assertive. They will no longer be too shy to tell you: "Hey, you are stubbing the wrong thing!". Let's reexamine our previous example, this time Bogus-style: it "returns the average score" do scores = fake(:scores, get: [5, 9]) students = fake(:students, all: ["John", "Mary"]) report_card = ReportCard.new(scores, students) expect(report_card.average_score).to eq(7) end Can you spot the difference? Not much, huh? However, the code above will not only make sure that the `ReportCard` works, it will also make sure that classes `Students` and `Scores` exist and have an interface that matches what you stub on them. ## DRY out your fake definitions By now you know how Bogus can help you with making sure that your stubs match the interface of your production classes. However, the attentive reader has probably spotted a problem with the solution above already. If all you need to change in your tests is the word `stub` to `fake` and give it some name, then how is that any better when it comes to scattering the fake interface definition all over your specs? The answer is: it's just slightly better. The reason it's better is that you only need to ever stub methods that return meaningful values. Let us explain. ### Tell-don't-ask methods Let's say we have a `PushNotifier` class: class PushNotifier def notify_async(messages) end end Now if you test an object that collaborates with our `PushNotifier`, you would do something like this: fake(:push_notifier) it "send push notifications when comment is added" do comment_adder = CommentAdder.new(push_notifier) comment_adder.add("Hello world!") expect(push_notifier).to have_received.notify_async("Comment: 'Hello world!' added.") end While not really impressive, this feature is worth mentioning because it will eliminate a lot of the mocking and stubbing from your tests. ### Global fake configuration Bogus also has a solution for DRYing stubbing of the methods that return values. All you need to do is to provide a reasonable default return value for those methods in the global fake configuration. Bogus.fakes do fake(:students) do all [] end fake(:scores) do get [] end end Now you will only need to stub those methods when you actually care about their return value, which is exactly what we want. ## Contract tests Bogus is not the only mocking library to implement fakes and safe mocking. However, it is the first library to implement the concept of contract tests [as defined by J. B. Rainsberger][contracts]. Let's start with an example: stub(scores).get(["John", "Mary"]) { [5, 9] } We already know that Bogus makes sure for us that the `Scores` class exists, has a `get` method and that this method can be called with one argument. It would also be nice to know that the input/output that we stub makes sense for this method. Contract tests are an idea, that whenever we stub `Scores#get` with argument `["John", "Mary"]` to return the value `[5, 9]`, we should add a test for the Scores class, that calls method `get` with those same arguments and have the same return value. A contract test like that could look like this: it "returns scrores for students" do scores = Scores.new(redis) scores.add("John", 5) scores.add("Mary", 9) expect(scores.get(["John", "Mary"])).to eq([5, 9]) end Obviously Bogus won't be able to write those tests for you. However it can remind you if you forget to add one. To add contract test verification, the only thing you need to do is add the line: verify_contract(:students) to your tests for `Students` class. ## Not only for people who use Dependency Injection The examples above all have one thing in common: they assume that your code has some way of injecting dependencies. We believe it should, and that's why we wrote [Dependor][dependor]. However, we are aware that this practice is not very common in the Ruby community. That's why Bogus supports replacing classes with fakes. Let's assume, that you have production code like this: class PushNotifier def self.notify_async(message) # ... end end class CommentAdder def self.add(parent, comment) PushNotifier.notify_async("comment added") # ... end end You can test it easily, with all the benefits of fakes, safe stubbing and contracts: describe CommentAdder do fake_class(PushNotifier) it "should send a push notification" do CommentAdder.add("the user", "the comment") expect(PushNotifier).to have_received.notify_async("comment added") end end describe PushNotifier do verify_contract(:push_notifier) it "notifies about comments asynchronously" do PushNotifier.notify_async("comment added") # ... end end [contracts]: http://www.infoq.com/presentations/integration-tests-scam [dependor]: https://github.com/psyho/dependor bogus-0.1.6/features/safe_stubbing/0000755000004100000410000000000012454377662017336 5ustar www-datawww-databogus-0.1.6/features/safe_stubbing/safe_mocking.feature0000644000004100000410000000457112454377662023347 0ustar www-datawww-dataFeature: Safe mocking In Bogus you normally use the following pattern to make sure right messages were sent between the tested object and it's collaborators: 1. Stub the collaborator method in let or before 2. In one test ensure that the tested method returns the right thing 3. In another test use `have_received` to ensure that the method on collaborator was called with right arguments. However, there are cases when the more general stub in let or before is not enough. Then, we can use mocking to reduce the amount of code written. The syntax for mocking is: mock(object).method_name(*args) { return_value } You can only mock methods that actually exist on an object. It will also work with methods that the object `responds_to?`, but (obviously) without being able to check the method signature. Background: Given a file named "library.rb" with: """ruby class Library def checkout(book) end end """ Scenario: Mocking methods that exist on real object Then spec file with following content should pass: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new mock(library).checkout("some book") { :checked_out } expect(library.checkout("some book")).to eq(:checked_out) end end """ Scenario: Mocking methods that do not exist on real object Then spec file with following content should fail: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new mock(library).buy("some book") { :bought } library.buy("some book") end end """ Scenario: Mocking methods with wrong number of arguments Then spec file with following content should fail: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new mock(library).checkout("some book", "another book") { :bought } library.checkout("some book", "another book") end end """ Scenario: Mocks require the methods to be called Then spec file with following content should fail: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new mock(library).checkout("some book") { :bought } end end """ bogus-0.1.6/features/safe_stubbing/readme.md0000644000004100000410000000207412454377662021120 0ustar www-datawww-dataBogus let's you stub methods on any object, not just fakes, which makes this feature usable even in scenarios when you don't follow the Inversion of Control Principle. When you stub/mock a method in Bogus, it will automatically ensure that: 1. The method actually exists 2. It can take the number of arguments you passed Those of you familiar with RR stubbing syntax, will feel right at home with Bogus: stub(object).method_name(*arguments) { return_value } One key difference is for when you want to stub a method for any arguments: # RR syntax stub(object).method_name { return_value } # Bogus syntax stub(object).method_name(any_args) { return_value } One other, quite important thing, is that Bogus does not erase the method signature when stubbing: class Library def self.checkout(book) end end The following would be OK in RR: stub(Library).checkout { "foo" } Library.checkout("a", "b") # returns "foo" But not in Bogus: stub(Library).checkout(any_args) { "foo" } Library.checkout("a", "b") # raises an error bogus-0.1.6/features/safe_stubbing/safe_stubbing.feature0000644000004100000410000000440512454377662023531 0ustar www-datawww-dataFeature: Safe stubbing Most Ruby test double libraries let you stub methods that don't exist. Bogus is different in this respect: not only does it not allow stubbing methods that don't exist, it also ensures that the number of arguments you pass to those methods matches the method definition. The stubbing syntax is: stub(object).method_name(arg1, arg2, ...) { return_value } Background: Given a file named "library.rb" with: """ruby class Library def checkout(book) end end """ Scenario: Stubbing methods that exist on real object Then spec file with following content should pass: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new stub(library).checkout("some book") { :checked_out } expect(library.checkout("some book")).to eq(:checked_out) end end """ Scenario: Stubbing methods that do not exist on real object Then spec file with following content should fail: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new stub(library).buy("some book") { :bought } end end """ Scenario: Stubbing methods with wrong number of arguments Then spec file with following content should fail: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new stub(library).checkout("some book", "another book") { :bought } end end """ Scenario: Stubs allow the methods to be called Then spec file with following content should pass: """ruby require_relative 'library' describe Library do it "does something" do library = Library.new stub(library).checkout("some book") { :bought } end end """ Scenario: Stubbing methods multiple times Then spec file with following content should fail: """ruby require_relative 'library' describe Library do it "stubbing with too many arguments" do library = Library.new stub(library).checkout("some book") { :bought } stub(library).checkout("book", "and one argument too many") { :whatever } end end """ bogus-0.1.6/features/safe_stubbing/spies.feature0000644000004100000410000000713612454377662022045 0ustar www-datawww-dataFeature: Spies Object Oriented Programming is all about messages sent between the objects. If you follow principles like "Tell, Don't Ask", you will enable yourself to combine Bogus's powerful feature of faking objects with it's ability to verify object interactions. Typically, stubbing libraries force you to first stub a method, so that you can later make sure it was called. However, if you use fakes, Bogus lets you verify that a method was called (or not) without stubbing it first. Background: Given a file named "library.rb" with: """ruby class Library def checkout(book) # marks book as checked out end end """ Given a file named "student.rb" with: """ruby class Student def initialize(library) @library = library end def study(*book_titles) book_titles.each do |book_title| @library.checkout(book_title) end end end """ Scenario: Ensuring methods were called Then spec file with following content should pass: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "studies using books from library" do student = Student.new(library) student.study("Moby Dick", "Sherlock Holmes") expect(library).to have_received.checkout("Moby Dick") expect(library).to have_received.checkout("Sherlock Holmes") end end """ Scenario: Spying on methods that do not exist Then spec file with following content should fail: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "studies using books from library" do student = Student.new(library) student.study("Moby Dick") expect(library).not_to have_received.return_book("Moby Dick") end end """ Scenario: Spying on methods with wrong number of arguments Then spec file with following content should fail: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "studies using books from library" do student = Student.new(library) student.study("Moby Dick", "Sherlock Holmes") expect(library).not_to have_received.checkout("Moby Dick", "Sherlock Holmes") end end """ Scenario: Spying on previously stubbed methods Then spec file with following content should pass: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "studies using books from library" do stub(library).checkout("Moby Dick") { "checked out" } expect(library.checkout("Moby Dick")).to eq("checked out") expect(library).to have_received.checkout("Moby Dick") end end """ Scenario: Spying on attribute writers Given a file named "canvas.rb" with: """ruby class Canvas def background_color=(color) # do something complicated end end """ Given a file named "popup.rb" with: """ruby class Popup def self.alert(message, canvas) canvas.background_color = "red" # display message end end """ Then spec file with following content should pass: """ruby require_relative 'canvas' require_relative 'popup' describe Popup do fake(:canvas) it "sets the background to red" do Popup.alert("No such file!", canvas) expect(canvas).to have_received(:background_color=, "red") end end """ bogus-0.1.6/features/safe_stubbing/argument_matchers.feature0000644000004100000410000000565112454377662024432 0ustar www-datawww-dataFeature: Argument matchers Bogus supports some argument matchers for use, when you don't really care about exact equality of arguments passed in or spied on. Background: Given a file named "catalog.rb" with: """ruby class Catalog def self.books_by_author_and_title(author, title) end end """ Scenario: Stubbing methods with any arguments Then the following test should pass: """ruby require_relative 'catalog' stub(Catalog).books_by_author_and_title(any_args) { :some_book } expect(Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes")).to eq(:some_book) """ Scenario: Stubbing methods with some wildcard arguments Then the following test should pass: """ruby require_relative 'catalog' stub(Catalog).books_by_author_and_title(any_args) { :some_book } stub(Catalog).books_by_author_and_title("Mark Twain", anything) { :twains_book } expect(Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer")).to eq(:twains_book) expect(Catalog.books_by_author_and_title("Mark Twain", "Huckleberry Finn")).to eq(:twains_book) expect(Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes")).to eq(:some_book) """ Scenario: Stubbing methods with proc arguments matcher Then the following test should pass: """ruby require_relative 'catalog' stub(Catalog).books_by_author_and_title(any_args) { :some_book } stub(Catalog).books_by_author_and_title(with{|author| author =~ /Twain/ }) { :twains_book } expect(Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer")).to eq(:twains_book) expect(Catalog.books_by_author_and_title("M. Twain", "Huckleberry Finn")).to eq(:twains_book) expect(Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes")).to eq(:some_book) """ Scenario: Stubbing methods with proc argument matcher Then the following test should pass: """ruby require_relative 'catalog' stub(Catalog).books_by_author_and_title(any_args) { :some_book } stub(Catalog).books_by_author_and_title(matches{|author| author =~ /Twain/ }, "Tom Sawyer") { :twains_book } expect(Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer")).to eq(:twains_book) expect(Catalog.books_by_author_and_title("M. Twain", "Huckleberry Finn")).to eq(:some_book) expect(Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes")).to eq(:some_book) """ Scenario: Stubbing methods with argument type matcher Then the following test should pass: """ruby require_relative 'catalog' stub(Catalog).books_by_author_and_title(any_args) { :some_book } stub(Catalog).books_by_author_and_title(any(String), any(String)) { :twains_book } expect(Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer")).to eq(:twains_book) expect(Catalog.books_by_author_and_title("M. Twain", :other_book)).to eq(:some_book) """ bogus-0.1.6/features/configuration/0000755000004100000410000000000012454377662017372 5ustar www-datawww-databogus-0.1.6/features/configuration/search_modules.feature0000644000004100000410000000174012454377662023746 0ustar www-datawww-dataFeature: search_modules Most projects do not have a separate namespace for their classes, which the default that Bogus assumes. However, if all (or some) of your classes exist within some module you can add it to the list of modules that Bogus will look in when trying to resolve class names. Scenario: search_modules Given a file named "foo.rb" with: """ruby class Foo def foo end end """ Given a file named "baz.rb" with: """ruby module Bar class Baz def baz end end end """ Then spec file with following content should pass: """ruby require_relative 'foo' require_relative 'baz' Bogus.configure do |c| c.search_modules << Bar end describe "logger class fake" do fake(:foo) fake(:baz) it "finds classes in global namespace" do foo.foo end it "finds classes in specified modules" do baz.baz end end """ bogus-0.1.6/features/configuration/readme.md0000644000004100000410000000027612454377662021156 0ustar www-datawww-dataBogus can be configured, similarly to many other frameworks with a configure block. Bogus.configure do |c| c.search_modules = [Object] c.fake_ar_attributes = true end bogus-0.1.6/features/configuration/fake_ar_attributes.feature0000644000004100000410000000347712454377662024620 0ustar www-datawww-dataFeature: fake_ar_attributes Instances of ActiveRecord::Base subclasses are different then most of the objects you might encounter because the field access on those classes is done by taking advantage of Ruby's `method_missing` functionality. Unfortunately, in order to create a fake, Bogus has to examine all of the methods that are defined on a given class and herein lies the problem, the methods that you would expect to have on your ActiveRecord models do not exist: class BlogPost < ActiveRecord::Base end blog_post = BlogPost.new blog_post.respond_to?(:name) # => true blog_post.method(:name) # raises NameError Normally, this would prevent Bogus from being able to fake those methods, but in the case of ActiveRecord we can figure out those fields by looking at the `BlogPost.columns` property. Based on that we can define those accessors on the created fake. If you wish to take advantage of that, you just need to flip a configuration switch: Bogus.configure do |c| c.fake_ar_attributes = true end Scenario: Adding missing accessors to AR classes Given a file named "blog_post.rb" with: """ruby require 'active_record' require 'nulldb' ActiveRecord::Schema.verbose = false ActiveRecord::Base.establish_connection :adapter => :nulldb ActiveRecord::Schema.define do create_table :blog_posts do |t| t.string :name t.string :tags end end class BlogPost < ActiveRecord::Base end Bogus.configure do |c| c.fake_ar_attributes = true end """ Then the following test should pass: """ruby require_relative 'blog_post' post = fake(:blog_post, name: "the name") stub(post).tags { "foo, bar" } expect(post.name).to eq("the name") expect(post.tags).to eq("foo, bar") """ bogus-0.1.6/features/contract_tests/0000755000004100000410000000000012454377662017562 5ustar www-datawww-databogus-0.1.6/features/contract_tests/contract_tests_mocks.feature0000644000004100000410000000531412454377662025375 0ustar www-datawww-dataFeature: Contract tests with mocks Whenever you mock something, you specify a contract on the arguments/return value pair. Bogus can check automatically whether this contract was satisfied. Background: Given a file named "library.rb" with: """ruby class Library def initialize @books = [] end def has_book?(book) @books.include?(book) end def checkout(book) @books.delete(book) end def return(book) @books << book end end """ Given a file named "student.rb" with: """ruby class Student def read(book, library = Library.new) if library.has_book?(book) library.checkout(book) end end end """ And a spec file named "student_spec.rb" with: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "checks out the book from library if it is available" do student = Student.new mock(library).has_book?("Moby Dick") { true } mock(library).checkout("Moby Dick") { "Moby Dick" } student.read("Moby Dick", library) end it "does not check out the book from library if not available" do student = Student.new mock(library).has_book?("Moby Dick") { false } student.read("Moby Dick", library) expect(library).not_to have_received.checkout("Moby Dick") end end """ Scenario: Fails when mocked methods are not called on real object Then spec file with following content should fail: """ruby require_relative 'library' describe Library do verify_contract(:library) let(:library) { Library.new } it "marks books as unavailable after they are checked out" do library.return("Moby Dick") library.checkout("Moby Dick") expect(library.has_book?("Moby Dick")).to be(false) end end """ Scenario: Verifies that mocked methods are called Then spec file with following content should pass: """ruby require_relative 'library' describe Library do verify_contract(:library) let(:library) { Library.new } it "allows checking out books that are in the inventory" do library.return("Moby Dick") expect(library.has_book?("Moby Dick")).to be(true) end it "does not allow checking out unavailable books" do expect(library.has_book?("Moby Dick")).to be(false) end it "marks books as unavailable after they are checked out" do library.return("Moby Dick") library.checkout("Moby Dick") expect(library.has_book?("Moby Dick")).to be(false) end end """ bogus-0.1.6/features/contract_tests/contract_tests_stubs.feature0000644000004100000410000000575312454377662025430 0ustar www-datawww-dataFeature: Contract tests with stubs Whenever you stub any method, a contract is specified on the input/output values of that method. When stubbing using the short syntax: fake(:fake_name, method_name: :return_value) the contract can only be specified on the return value. The longer syntax: stub(fake).method_name(args) { :return_value } will also create a contract on the method input parameters. Background: Given a file named "library.rb" with: """ruby class Library def initialize @books = [] end def has_book?(book) @books.include?(book) end def checkout(book) @books.delete(book) end def return(book) @books << book end end """ Given a file named "student.rb" with: """ruby class Student def read(book, library = Library.new) if library.has_book?(book) library.checkout(book) end end end """ And a spec file named "student_spec.rb" with: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "checks out the book from library if it is available" do student = Student.new stub(library).has_book?("Moby Dick") { true } student.read("Moby Dick", library) expect(library).to have_received.checkout("Moby Dick") end it "does not check out the book from library if not available" do student = Student.new stub(library).has_book?("Moby Dick") { false } student.read("Moby Dick", library) expect(library).not_to have_received.checkout("Moby Dick") end end """ Scenario: Fails when stubbed methods are not called on real object Then spec file with following content should fail: """ruby require_relative 'library' describe Library do verify_contract(:library) let(:library) { Library.new } it "marks books as unavailable after they are checked out" do library.return("Moby Dick") library.checkout("Moby Dick") expect(library.has_book?("Moby Dick")).to be(false) end end """ Scenario: Verifies that stubbed methods are called Then spec file with following content should pass: """ruby require_relative 'library' describe Library do verify_contract(:library) let(:library) { described_class.new } it "allows checking out books that are in the inventory" do library.return("Moby Dick") expect(library.has_book?("Moby Dick")).to be(true) end it "does not allow checking out unavailable books" do expect(library.has_book?("Moby Dick")).to be(false) end it "marks books as unavailable after they are checked out" do library.return("Moby Dick") library.checkout("Moby Dick") expect(library.has_book?("Moby Dick")).to be(false) end end """ bogus-0.1.6/features/contract_tests/readme.md0000644000004100000410000000255412454377662021347 0ustar www-datawww-dataWhenever you write test code like this: mock(library).checkout("Moby Dick") { raise NoSuchBookError } There are some assumptions this code makes: 1. There is an object in my system that can play the role of a library. 2. The library object has a `#checkout` method that takes one argument. 3. The system under test is supposed to call `#checkout` with argument `"Moby Dick"` at least once. 4. There is some context in which, given argument "Moby Dick", the `#checkout` method raises `NoSuchBookError`. While using fakes makes sure that the assumptions 1 and 2 are satisfied, and assumption number 3 is verified by the mocking system, in order to make sure that the assumption no 4 is also true, you need to write a test for the library object. Bogus will not be able to write that test for you, but it can remind you that you should do so. Whenever you use named fakes: fake(:library) Bogus will remember any interactions set up on that fake. If you want to verify that you remembered to test all the scenarios specified by stubbing/spying/mocking on the fake object, you can put the following code in the tests for "the real thing" (i.e. the Library class in our example): verify_contract(:library) This will record all of the interactions you make with that class and make the tests fail if you forget to test some scenario that you recorded using a fake object. bogus-0.1.6/features/contract_tests/custom_overwritten_class.feature0000644000004100000410000000577212454377662026321 0ustar www-datawww-dataFeature: Customizing the overwritten class Typically, when you specify a contract to be verified, you do it like this: describe SomeClass do verify_contract(:some_fake_name) end When you do this, under the hood Bogus replaces `SomeClass` with a proxy that records any calls made to the class and its instances for the duration of the test. If the class you want to be overwritten is not the one that is described, you can customize it like so: describe "not a class" do verify_contract(:some_fake_name) { SomeClass } end In case there is no described class and you don't provide a custom one to be overwritten, the class will be guessed based on the name of the fake: describe "not a class" do verify_contract(:some_fake_name) end In the above example, Bogus will try to overwrite a class named `SomeFakeName`. Background: Given a file named "library.rb" with: """ruby class PublicLibrary def initialize @books = [] end def has_book?(book) @books.include?(book) end def checkout(book) @books.delete(book) end def return(book) @books << book end end """ Given a file named "student.rb" with: """ruby class Student def read(book, library = PublicLibrary.new) if library.has_book?(book) library.checkout(book) end end end """ And a spec file named "student_spec.rb" with: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) { PublicLibrary } it "checks out the book from library if it is available" do student = Student.new mock(library).has_book?("Moby Dick") { true } mock(library).checkout("Moby Dick") { "Moby Dick" } student.read("Moby Dick", library) end it "does not check out the book from library if not available" do student = Student.new mock(library).has_book?("Moby Dick") { false } student.read("Moby Dick", library) expect(library).not_to have_received.checkout("Moby Dick") end end """ Scenario: Verifying contract for a class that is not the described_class Then spec file with following content should pass: """ruby require_relative 'library' describe "Borrowing books from library" do verify_contract(:library) { PublicLibrary } let(:library) { PublicLibrary.new } it "allows checking out books that are in the inventory" do library.return("Moby Dick") expect(library.has_book?("Moby Dick")).to be(true) end it "does not allow checking out unavailable books" do expect(library.has_book?("Moby Dick")).to be(false) end it "marks books as unavailable after they are checked out" do library.return("Moby Dick") library.checkout("Moby Dick") expect(library.has_book?("Moby Dick")).to be(false) end end """ bogus-0.1.6/features/contract_tests/contract_tests_spies.feature0000644000004100000410000000362612454377662025410 0ustar www-datawww-dataFeature: Contract tests with spies Whenever you spy on method invocations, it creates a contract specifying that some method can be called with a particular set of arguments. It can be automatically verified by Bogus, whether the method was actually called with those arguments. Background: Given a file named "library.rb" with: """ruby class Library def checkout(book) end end """ Given a file named "student.rb" with: """ruby class Student def read(book, library = Library.new) library.checkout(book) # ... end end """ And a spec file named "student_spec.rb" with: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "reads books from library" do student = Student.new student.read("Moby Dick", library) expect(library).to have_received.checkout("Moby Dick") end end """ Scenario: Stubbing methods that exist on real object Then spec file with following content should pass: """ruby require_relative 'library' describe Library do verify_contract(:library) it "checks out books" do library = Library.new library.checkout("Moby Dick") # ... end end """ Scenario: Verifing that stubbed methods are tested Then spec file with following content should fail: """ruby require_relative 'library' describe Library do verify_contract(:library) end """ Scenario: Verifying that methods are tested with right arguments Then spec file with following content should fail: """ruby require_relative 'library' describe Library do verify_contract(:library) it "checks out books" do library = Library.new library.checkout("Moby Dick 2: The ulitmate") # ... end end """ bogus-0.1.6/features/contract_tests/return_value_contracts.feature0000644000004100000410000000614112454377662025734 0ustar www-datawww-dataFeature: Return value contracts In order to be able to record the stubbed value, Bogus requires that the block you pass when stubbing is free of side effects and idempotent. If it's not, the behavior of contract verification is not defined. Background: Given a file named "session_controller.rb" with: """ruby class SessionController def initialize(authentication_service) @authentication_service = authentication_service end def create(params) @authentication_service.authenticate(params[:login], params[:password]) :render_welcome rescue :render_error end end """ Given a file named "authentication_service.rb" with: """ruby class AuthenticationService def initialize(user_db) @user_db = user_db end def authenticate(login, password) unless @user_db[login] == Digest::SHA1.hexdigest(password) raise WrongPassword end end end class WrongPassword < StandardError end """ And a spec file named "session_controller_spec.rb" with: """ruby require_relative 'session_controller' require_relative 'authentication_service' describe SessionController do fake(:authentication_service) let(:controller) { SessionController.new(authentication_service) } it "logs in the user with valid data" do stub(authentication_service).authenticate('foo', 'bar') expect(controller.create(login: 'foo', password: 'bar')).to eq(:render_welcome) end it "fails with invalid data" do stub(authentication_service).authenticate('baz', 'bar') { raise WrongPassword } expect(controller.create(login: 'baz', password: 'bar')).to eq(:render_error) end end """ Scenario: Bogus makes sure that all the return values recorded by stubbing are also present in tests of the real object Then spec file with following content should fail: """ruby require_relative 'authentication_service' describe AuthenticationService do verify_contract(:authentication_service) it "logs in the user" do service = AuthenticationService.new('foo' => Digest::SHA1.hexdigest('bar')) expect { service.authenticate('foo', 'bar') }.not_to raise_error end end """ Scenario: Bogus does not fail the tests if all the recorded values have been also recorded on the real object Then spec file with following content should pass: """ruby require_relative 'authentication_service' describe AuthenticationService do verify_contract(:authentication_service) it "logs in the user" do service = AuthenticationService.new('foo' => Digest::SHA1.hexdigest('bar')) expect { service.authenticate('foo', 'bar') }.not_to raise_error end it "raises WrongPassword with incorrect credentials" do service = AuthenticationService.new('foo' => Digest::SHA1.hexdigest('bar')) expect { service.authenticate('baz', 'bar') }.to raise_error(WrongPassword) end end """ bogus-0.1.6/features/minitest_support.feature0000644000004100000410000001306312454377662021533 0ustar www-datawww-dataFeature: minitest support minitest is supported by Bogus both with the classic assert-style syntax and the minitest/spec expectation syntax. Background: Given a file named "library.rb" with: """ruby class Library def self.books end def checkout(book) end def return_book(book) end end """ Given a file named "book_index.rb" with: """ruby class BookIndex def self.by_author(author) Library.books.select{|book| book[:author] == author} end end """ Given a file named "student.rb" with: """ruby class Student def initialize(library) @library = library end def study(*book_titles) book_titles.each do |book_title| @library.checkout(book_title) end end end """ Scenario: Auto-verification of unsatisfied mocks Then minitest file "student_test.rb" with the following content should fail: """ruby require 'minitest/autorun' require 'bogus/minitest' require_relative 'student' require_relative 'library' class StudentTest < MiniTest::Unit::TestCase def test_library_checkouts library = fake(:library) student = Student.new(library) mock(library).checkout("Moby Dick") mock(library).checkout("Sherlock Holmes") student.study("Moby Dick") end end """ Scenario: Spying on method calls with assert syntax Then minitest file "student_test.rb" with the following content should pass: """ruby require 'minitest/autorun' require 'bogus/minitest' require_relative 'student' require_relative 'library' class StudentTest < MiniTest::Unit::TestCase def setup @library = fake(:library) end def test_library_checkouts student = Student.new(@library) student.study("Moby Dick", "Sherlock Holmes") assert_received @library, :checkout, ["Moby Dick"] assert_received @library, :checkout, ["Sherlock Holmes"], "optional message" refute_received @library, :return_book, ["Moby Dick"] end end """ Scenario: Spying on method calls with expectation syntax Then minitest file "student_spec.rb" with the following content should pass: """ruby require 'minitest/autorun' require 'bogus/minitest/spec' require_relative 'student' require_relative 'library' describe Student do describe "#study" do fake(:library) it "studies using books from library" do student = Student.new(library) student.study("Moby Dick", "Sherlock Holmes") library.must_have_received :checkout, ["Moby Dick"] library.must_have_received :checkout, ["Sherlock Holmes"] library.wont_have_received :return_book, ["Moby Dick"] end end end """ Scenario: Describe-level class faking Then minitest file "book_index_spec.rb" with the following content should pass: """ruby require 'minitest/autorun' require 'bogus/minitest/spec' require_relative 'book_index' require_relative 'library' describe BookIndex do fake_class(Library, books: []) it "returns books written by author" do BookIndex.by_author("Mark Twain").must_equal [] end end """ Scenario: Negative contract verification Then minitest file "student_and_library_spec.rb" with the following content should fail: """ruby require 'minitest/autorun' require 'bogus/minitest/spec' require_relative 'student' require_relative 'library' describe Student do describe "#study" do fake(:library) it "studies using books from library" do Student.new(library).study("Moby Dick") library.must_have_received :checkout, ["Moby Dick"] end end end describe Library do verify_contract(:library) end """ Scenario: Positive contract verification Then minitest file "student_and_library_spec.rb" with the following content should pass: """ruby require 'minitest/autorun' require 'bogus/minitest/spec' require_relative 'student' require_relative 'library' describe Student do describe "#study" do fake(:library) it "studies using books from library" do Student.new(library).study("Moby Dick") library.must_have_received :checkout, ["Moby Dick"] end end end describe Library do verify_contract(:library) describe '#checkout' do it "checks books out" do Library.new.checkout("Moby Dick") end end end """ Scenario: Custom verified class Then minitest file "student_and_library_spec.rb" with the following content should pass: """ruby require 'minitest/autorun' require 'bogus/minitest/spec' class NetworkLogger def info(msg) end end class OrderProcessor def process(order, logger = NetworkLogger.new) logger.info("#{order} processed") end end describe OrderProcessor do describe "#process" do fake(:logger) { NetworkLogger } it "processes orders" do OrderProcessor.new.process("burger & fries", logger) logger.must_have_received :info, ["burger & fries processed"] end end end describe "Using network logger" do verify_contract(:logger) { NetworkLogger } describe '#info' do it "logs on info level" do NetworkLogger.new.info("burger & fries processed") end end end """ bogus-0.1.6/features/getting_started.md0000644000004100000410000000146612454377662020243 0ustar www-datawww-data## Installation To install Bogus, all you need to do is add: gem "bogus" to your Gemfile. ## Configuration In your `spec_helper.rb`, require bogus: require 'bogus/rspec' Bogus will hook into RSpec on it's own, but if you want to be explicit about the used mock framework, you can put this in your `spec_helper.rb`: RSpec.configure do |c| # already done by requiring bogus/rspec c.mock_with Bogus::RSpecAdapter end And configure it to look for classes in your namespace: Bogus.configure do |c| c.search_modules << My::Namespace end You will probably also want to create a configuration file for your fakes (for example `spec/support/fakes.rb`): Bogus.fakes do # fakes go here end and require it in your gem file: require_relative 'support/fakes.rb' bogus-0.1.6/features/fakes/0000755000004100000410000000000012454377662015614 5ustar www-datawww-databogus-0.1.6/features/fakes/replacing_classes.feature0000644000004100000410000000767212454377662022666 0ustar www-datawww-dataFeature: Replacing classes with fakes Bogus is an opinionated piece of software. One of the opinions we have is that you should use dependency injection to make your code more modular and your classes easier to compose. However, we respect the fact, that this is currently not very popular among Ruby developers. In order to make life easier for people who choose not to use Dependency Injection, Bogus makes it convenient to replace chosen classes in your tests with fakes. All you need to do, is put the following code in your describe: fake_class(FooBar, foo: "bar") Which is a shortcut for: before do fake_class(FooBar, foo: "bar") end Background: Given a file named "app.rb" with: """ruby require "yaml" class Library FILE = "library.yml" def self.books YAML.load_file(FILE) end end class BookIndex def self.by_author(author) Library.books.select{|book| book[:author] == author} end end """ And a file named "spec_helper.rb" with: """ruby require 'bogus/rspec' require_relative 'app' """ Scenario: Replacing classes and contracts Given a file named "library_spec.rb" with: """ruby require_relative 'spec_helper' require 'fileutils' describe Library do verify_contract(:library) it "reads the books from the yaml file" do books = [{name: "Tom Sawyer", author: "Mark Twain"}, {name: "Moby Dick", author: "Herman Melville"}] File.open(Library::FILE, "w") { |f| f.print books.to_yaml } expect(Library.books).to eq(books) end after do FileUtils.rm_rf(Library::FILE) end end """ And a file named "book_index_spec.rb" with: """ruby require_relative 'spec_helper' describe BookIndex do verify_contract(:book_index) it "returns books written by author" do tom_sawyer = {name: "Tom Sawyer", author: "Mark Twain"} moby_dick = {name: "Moby Dick", author: "Herman Melville"} fake_class(Library, books: [tom_sawyer, moby_dick]) expect(BookIndex.by_author("Mark Twain")).to eq([tom_sawyer]) end end """ When I run `rspec book_index_spec.rb library_spec.rb` Then the specs should pass Scenario: Replacing classes and contracts with a different fake name Given a file named "library_spec.rb" with: """ruby require_relative 'spec_helper' require 'fileutils' describe Library do verify_contract(:book_repository) it "reads the books from the yaml file" do books = [{name: "Tom Sawyer", author: "Mark Twain"}, {name: "Moby Dick", author: "Herman Melville"}] File.open(Library::FILE, "w") { |f| f.print books.to_yaml } expect(Library.books).to eq(books) end after do FileUtils.rm_rf(Library::FILE) end end """ And a file named "book_index_spec.rb" with: """ruby require_relative 'spec_helper' describe BookIndex do verify_contract(:book_index) it "returns books written by author" do tom_sawyer = {name: "Tom Sawyer", author: "Mark Twain"} moby_dick = {name: "Moby Dick", author: "Herman Melville"} fake_class(Library, fake_name: :book_repository, books: [tom_sawyer, moby_dick]) expect(BookIndex.by_author("Mark Twain")).to eq([tom_sawyer]) end end """ When I run `rspec book_index_spec.rb library_spec.rb` Then the specs should pass Scenario: Replacing classes with a macro Given a file named "book_index_spec.rb" with: """ruby require_relative 'spec_helper' describe BookIndex do fake_class(Library, books: []) it "returns books written by author" do expect(BookIndex.by_author("Mark Twain")).to eq([]) end end """ When I run `rspec book_index_spec.rb` Then the specs should pass bogus-0.1.6/features/fakes/readme.md0000644000004100000410000000210712454377662017373 0ustar www-datawww-dataFakes in Bogus are essentially lightweight objects that mimic the original object's interface. Let's say that we have a `Library` class that is used to manage books and a `Student`, who can interact with the `Library` in some way. In order to test the `Student` in isolation, we need to replace the `Library`, with some test double. Typically, you would do that by creating an anonymous stub/mock object and stubbing the required methods on it. Using those stubs, you specify the desired interface of the library object. The problems with that approach start when you change the `Library` class. For example, you could rename the `#checkout` method to `#checkout_book`. If you used the standard approach, where your stubs are not connected in any way to the real implementation, your tests will keep happily passing, even though the collaborator interface just changed. Bogus saves you from this problem, because your fakes have the exact same interface as the real collaborators, so whenever you change the collaborator, but not the tested object, you will get an exception in your tests. bogus-0.1.6/features/fakes/duck_types.feature0000644000004100000410000000764512454377662021357 0ustar www-datawww-dataFeature: Faking duck types Sometimes, your system contains more than one class that can satisfy a given role. Which of the possible implementations do you pick then, and how can you make sure that their interfaces stay in sync? Bogus gives you a way of extracting the "lowest common interface" out of multiple classes. All you need to do is just pass the classes in question to the `make_duck` method: make_duck(DatabaseLogger, NetworkLogger, DevNullLogger) This call will return a new class, that contains only the methods that exist in the public interface of all of the given classes, and in all of them have the same signature. To make things easier for you, Bogus will automatically make a duck type for you, every time you return multiple classes from fake: fake(:logger) { [DatabaseLogger, NetworkLogger, DevNullLogger] } It is of course also possible to do the same thing in the global fake configuration: Bogus.fakes do fake :logger, class: proc{ [DatabaseLogger, NetworkLogger, DevNullLogger] } end Background: Given a file named "loggers.rb" with: """ruby class DatabaseLogger def error(message); end def warn(message, level); end def connection; end end class NetworkLogger def error(message); end def warn(message, level); end def socket; end end class DevNullLogger def error(message); end def warn(message, level); end def debug(message); end end class ExceptionNotifier def initialize(logger) @logger = logger end def notify(exception) @logger.error(exception) end end """ Scenario: Copying instance methods Then spec file with following content should pass: """ruby require_relative 'loggers' describe "make_duck" do let(:duck) { make_duck(DatabaseLogger, NetworkLogger, DevNullLogger) } let(:duck_instance) { duck.new } it "responds to error" do expect(duck_instance).to respond_to(:error) end it "has arity 1 for error" do expect(duck_instance.method(:error).arity).to eq(1) end it "responds to warn" do expect(duck_instance).to respond_to(:warn) end it "has arity 2 for warn" do expect(duck_instance.method(:warn).arity).to eq(2) end it "does not respond to connection" do expect(duck_instance).not_to respond_to(:connection) end it "does not respond to socket" do expect(duck_instance).not_to respond_to(:socket) end it "does not respond to debug" do expect(duck_instance).not_to respond_to(:debug) end end """ Scenario: Faking duck types Then spec file with following content should pass: """ruby require_relative 'loggers' describe "fake with multiple classes" do fake(:logger) { [DatabaseLogger, NetworkLogger, DevNullLogger] } let(:notifier) { ExceptionNotifier.new(logger) } it "logs the exception" do notifier.notify("whoa!") expect(logger).to have_received.error("whoa!") end end """ Scenario: Globally configured duck types Given a file named "fakes.rb" with: """ruby Bogus.fakes do logger_implementations = proc{ [DatabaseLogger, NetworkLogger, DevNullLogger] } fake :logger, class: logger_implementations end """ Then spec file with following content should pass: """ruby require_relative 'fakes' require_relative 'loggers' describe "fake with multiple classes" do fake(:logger) let(:notifier) { ExceptionNotifier.new(logger) } it "logs the exception" do notifier.notify("whoa!") expect(logger).to have_received.error("whoa!") end end """ bogus-0.1.6/features/fakes/fake_objects.feature0000644000004100000410000000724512454377662021620 0ustar www-datawww-dataFeature: Faking existing classes You create a fake by calling the `fake` method: fake(fake_name, options) { ClassToCopy } If you omit the fake_name, you will get an anonymous fake, otherwise the name will be used to identify the fake for the purposes of contract tests. If you omit the block returning the class to copy, fake name will also be used to guess that. Usually you will want the fake to return an instance of the copied class. Otherwise, you can pass `:as => :class` option to copy the class and return the copy, not an instance of it. Options can also include methods to stub on the returned fake, which makes: fake(:foo, bar: "value") Equivalent to: foo = fake(:foo) stub(foo).bar(any_args) { "value" } For your convenience, Bogus also defines the following macro: fake(:foo, bar: "value") Which is equivalent to: let(:foo) { fake(:foo, bar: "value") } Background: Given a file named "library.rb" with: """ruby class Library def checkout(book) end def return_book(book) end def self.look_up(book) end end """ Given a file named "student.rb" with: """ruby class Student def self.learn(library = Library.new) library.checkout("hello world") true end end """ Scenario: Calling methods that exist on real object Then spec file with following content should pass: """ruby require_relative 'student' require_relative 'library' describe Student do fake(:library) it "does something" do expect(Student.learn(library)).to be(true) end end """ Scenario: Taking the guesswork out of finding a class to copy Then spec file with following content should pass: """ruby class PublicLibrary def checkout(book) end end describe "logger fake" do fake(:library) { PublicLibrary } it "uses the class provided in block instead of the guessed one" do expect(library.class.name).to eq("PublicLibrary") end end """ Scenario: Fakes which are classes Then spec file with following content should pass: """ruby require_relative 'library' describe "library class fake" do fake(:library, as: :class) it "is a class" do expect(library).to be_a(Class) end it "has the same name as original class" do expect(library.name).to eq(Library.name) end it "has same methods as original class" do library.look_up('something') end end """ Scenario: Fakes with inline return values Then spec file with following content should pass: """ruby require_relative 'library' describe "library class fake" do let(:library) { fake(:library, checkout: "checked out", return_book: "returned") } it "sets the default return value for provided functions" do expect(library.checkout("Moby Dick")).to eq("checked out") expect(library.checkout("Three Musketeers")).to eq("checked out") expect(library.return_book("Moby Dick")).to eq("returned") expect(library.return_book("Three Musketeers")).to eq("returned") end end """ Scenario: Fakes are identified as instances of the faked class Then spec file with following content should pass: """ruby require_relative 'library' def library?(object) case object when Library true else false end end describe "library class fake" do fake(:library) it "is identified as Library" do expect(library?(library)).to be(true) end end """ bogus-0.1.6/features/fakes/anonymous_doubles.feature0000644000004100000410000001060112454377662022734 0ustar www-datawww-dataFeature: Anonymous test doubles Anonymous test doubles can be useful as a stepping stone towards actual fakes and when migrating from another testing library. In contrast with other testing libraries, Bogus makes its fakes respond to all methods by default. This way you can spy on methods without stubbing them first. It is not advisable to use those for anything else than an intermediate step. Fakes that mimic an actual class have many more benefits. The syntax for defining fakes is: fake(method_1: return_value, method_2: proc{return_value2}) If you pass a proc as a return value to a fake, the proc will be called to obtain the value. This can be used for instance to raise errors in stubbed methods. If you want to actually return a proc from a method, you need to use a slightly longer syntax: factory = fake() stub(factory).make_validator{ proc{ false } } Background: Given a file named "student.rb" with: """ruby class Student attr_reader :library_card def initialize(name) @name = name end def sign_up(library) @library_card = library.register_junior(@name) end end """ Scenario: Stubbing any method with any parameters Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } let(:jake) { Student.new("Jake") } it "allows stubbing any method with any parameters" do stub(library).register_junior(any_args) { "the card" } jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Stubbing methods in initializer Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake(register_junior: "the card") } let(:jake) { Student.new("Jake") } it "allows stubbing any method with any parameters" do jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Stubbing methods inline by passing a block Then the following test should pass: """ruby library = fake(register_junior: proc{ raise "library full!" }) expect { library.register_junior("Jake") }.to raise_error("library full!") """ Scenario: Mocking any method with any parameters Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } let(:jake) { Student.new("Jake") } it "allows mocking any method with any parameters" do mock(library).register_junior("Jake") { "the card" } jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Mocking any method with any parameters Then spec file with following content should fail: """ruby require_relative 'student' describe Student do it "allows stubbing any method with any parameters" do library = fake mock(library).register_junior { "the card" } end end """ Scenario: Stubbing methods in initializer Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake(register_junior: "the card") } let(:jake) { Student.new("Jake") } it "allows stubbing any method with any parameters" do jake.sign_up(library) expect(jake.library_card).to eq("the card") end end """ Scenario: Spying on method calls Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } let(:jake) { Student.new("Jake") } it "allows spying on any method" do jake.sign_up(library) expect(library).to have_received.register_junior("Jake") end end """ Scenario: Invoking arbitrary methods Then spec file with following content should pass: """ruby require_relative 'student' describe Student do let(:library) { fake } it "allows calling any method with any parameters" do expect { library.foo library.bar("hello") library.baz(1, 2, 3, 4, 5) }.not_to raise_error end end """ bogus-0.1.6/features/fakes/global_fake_configuration.feature0000644000004100000410000000564412454377662024357 0ustar www-datawww-dataFeature: Global fake configuration In an ideal world, all the fakes would follow the tell-don't-ask principle, which would eliminate the need for stubbing, and would be instances of classes that match the fake name, which would eliminate the need for configuration of things like (`as: :class` / `as: :instance`). However, in reality we often need to add this kind of configuration to our fake definitions, and the more collaborators a fake has, the more duplication we introduce this way. To eliminate this duplication, Bogus comes with a DSL to configure the fakes in one place, and unify their use in all your tests. To globally configure your fakes, all you need to do is to place code like this: Bogus.fakes do fake(:fake_name, as: :class, class: proc{SomeClass}) do method_1 { return_value_1 } method_2 return_value_2 end end in your spec helper, or a file required from it. Background: Given a file named "public_library.rb" with: """ruby class PublicLibrary def self.books_by_author(name) end end """ Given a file named "fakes.rb" with: """ruby Bogus.fakes do fake(:library, as: :class, class: proc{PublicLibrary}) do books_by_author [] end end """ Scenario: Globally configured fakes have all the properties configured Then spec file with following content should pass: """ruby require_relative "fakes" require_relative "public_library" describe "The library fake" do fake(:library) it "is a class" do # because of the as: :class specified in the fake definition expect(library).to be_an_instance_of(Class) end it "is a copy of PublicLibrary" do # because of the block passed into configuration expect(library.name).to eq("PublicLibrary") end it "returns has stubbed books_by_author" do # because of the inline-stubbed books_by_author expect(library.books_by_author("Mark Twain")).to eq([]) end end """ Scenario: Overwriting stubbed methods using fake macro Then spec file with following content should pass: """ruby require_relative "fakes" require_relative "public_library" describe "The library fake" do fake(:library, books_by_author: ["Some Book"]) it "can be overridden in the shortcut definition" do expect(library.books_by_author("Charles Dickens")).to eq(["Some Book"]) end end """ Scenario: Overwriting stubbed methods using fake helper function Then spec file with following content should pass: """ruby require_relative "fakes" require_relative "public_library" describe "The library fake" do it "can be overridden in the helper" do library = fake(:library, books_by_author: ["Some Book"]) expect(library.books_by_author("Charles Dickens")).to eq(["Some Book"]) end end """ bogus-0.1.6/features/changelog.md0000644000004100000410000000535212454377662017001 0ustar www-datawww-data## 0.1.6 - Removed dependency on Coveralls::SimpleCov::Formatter (thanks to Ken Dreyer) - Made all tests pass on Rubinious - Updated tests to use RSpec Mocks instead of RR in unit tests - Updated tests to use RSpec 3 - Fixed described_class in RSpec 3.* ## 0.1.5 - Made it possible to use fake objects in case/when statements (override ===) - Allowed stubbing methods defined on Object, such as #to_json - Added `matches` - for matching single arguments when stubbing - Updated RSpec syntax in specs and features (thanks to Michael Durrant) - Done some housekeeping around development dependencies/Gemfile.lock/TravisCI configuration (thanks to Ken Dreyer) - Removed deprecation warnings when using Bogus with RSpec 3.0 (thanks to Michal Muskala) - Added support for Ruby 2.1 required keyword arguments (thanks to Indrek Juhkam) - Fixed a bug that made it impossible to stub .new on fake classes ## 0.1.4 - Support for contracts in minitest - Allowed customizing the class being overwritten by verify_contract - Fixed is_a? behavior for fakes - Fake#is_a? now returns true for superclasses of and modules included into the faked class. - Reorganized the code into subdirectories ## 0.1.3 - Support for minitest - Support nested constants in faked classes - Fixed error in RSpec < 2.14 ## 0.1.2 - Removed rspec warning about backtrace_clean_patterns ## 0.1.1 - Minor bugfixes to Ruby 2.0 support - Support for Rubinius (head) and JRuby - Overwrite described_class in on verify_contract - Added with{} and any(Klass) argument matchers - Added have_received(:name, args) syntax ## 0.1.0 - Support for stubbing on frozen fakes - Safe stubbing of constructors - Fixed spying on anonymous fakes - Automatic handling of ActiveRecord columns - Support Ruby 2.0 keyword arguments ### Breaking changes: - Fakes no longer return themselves from unstubbed method calls, because this was often a source of confusion. In the new version we return a Bogus::UndefinedReturnValue which contains the method name and arguments from where it was returned. ## 0.0.4 - Support mocking methods with optional parameters ## 0.0.3 - Global fake configuration - Inline method stubbing syntax - Removed dependency on RR - verifies_contracts records on described_class instead of class based on fake name - Replacing classes with fakes - Extracting common interface out of multpile classes to create duck types ## 0.0.2 - Makes it possible to stub method calls on objects that utilize method missing. - Removed the need to require both bogus and bogus/rspec. - Implemented anonymous fakes. - Fixed a bug in copying ActiveRecord classes. - (internal) Replaced autoloads with require. ## 0.0.1 Initial version. - Fakes. - Safe spying, stubbing, mocking. - Veryfying contracts defined by test doubles. bogus-0.1.6/features/authors.md0000644000004100000410000000217312454377662016535 0ustar www-datawww-data## Adam Pohorecki github: [psyho][psyho] twitter: [@apohorecki][apohorecki] blog: [adam.pohorecki.pl][blog] ## Paweł Pierzchała github: [wrozka][wrozka] twitter: [@zwrozka][zwrozka] ## Piotr Szotkowski github: [chastell][chastell] twitter: [@chastell][chastell-twitter] ## Marek Nowak github: [yundt][yundt] twitter: [@yundt][yundt-twitter] ## Contract tests The contract tests feature was inspired by [J. B. Rainsberger's talk: "Integration Tests are a Scam"][scam]. ## Mocking DSL syntax The mocking DSL syntax was inspired by the [RR framework][rr]. ## Sponsor The development of Bogus was partially sponsored by [Lunar Logic][llp]. [llp]: http://www.lunarlogicpolska.com [psyho]: https://github.com/psyho [apohorecki]: http://twitter.com/apohorecki [blog]: http://adam.pohorecki.pl [wrozka]: https://github.com/wrozka [zwrozka]: http://twitter.com/zwrozka [chastell]: https://github.com/chastell [chastell-twitter]: http://twitter.com/chastell [yundt]: https://github.com/yundt [yundt-twitter]: http://twitter.com/yundt [scam]: http://www.infoq.com/presentations/integration-tests-scam [rr]: https://github.com/btakita/rr bogus-0.1.6/features/.nav0000644000004100000410000000140112454377662015304 0ustar www-datawww-data- getting_started.md (Getting Started) - readme.md (Introduction to Bogus) - fakes (Fakes): - fake_objects.feature - global_fake_configuration.feature - anonymous_doubles.feature - replacing_classes.feature - duck_types.feature - safe_stubbing (Safe Stubbing): - safe_mocking.feature - safe_stubbing.feature - spies.feature - argument_matchers.feature - active_record.feature - contract_tests (Contract Tests): - contract_tests_mocks.feature - contract_tests_stubs.feature - contract_tests_spies.feature - return_value_contracts.feature - custom_overwritten_class.feature - configuration (Configuration Options): - search_modules.feature - fake_ar_attributes.feature - minitest_support.feature - changelog.md - license.md - authors.md bogus-0.1.6/features/support/0000755000004100000410000000000012454377662016237 5ustar www-datawww-databogus-0.1.6/features/support/env.rb0000644000004100000410000000071112454377662017353 0ustar www-datawww-datarequire 'aruba/cucumber' require 'aruba/jruby' Before('@known_bug') do pending("This scenario fails because of a known bug") end Before do |scenario| dir_name = "scenario-#{rand(1_000_000)}" create_dir(dir_name) cd(dir_name) end Before do @aruba_timeout_seconds = 60 end if RUBY_PLATFORM == 'java' && ENV['TRAVIS'] Aruba.configure do |config| config.before_cmd do set_env('JAVA_OPTS', "#{ENV['JAVA_OPTS']} -d64") end end end bogus-0.1.6/license.md0000644000004100000410000000210012454377662014642 0ustar www-datawww-data# The MIT License (MIT) Copyright (c) 2012-2013 Adam Pohorecki Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bogus-0.1.6/rbs.sh0000755000004100000410000000011112454377662014023 0ustar www-datawww-data#!/bin/bash rvm 1.9.2@bogus,1.9.3@bogus,rbx19@bogus,jruby@bogus exec $@ bogus-0.1.6/.rspec0000644000004100000410000000001012454377662014011 0ustar www-datawww-data--color bogus-0.1.6/bogus.gemspec0000644000004100000410000000321712454377662015374 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "bogus/version" Gem::Specification.new do |s| s.name = "bogus" s.version = Bogus::VERSION s.authors = ["Adam Pohorecki"] s.email = ["adam@pohorecki.pl"] s.license = 'MIT' s.homepage = "https://github.com/psyho/bogus" s.summary = %q{Create fakes to make your isolated unit tests reliable.} s.description = %q{Decreases the need to write integration tests by ensuring that the things you stub or mock actually exist.} s.rubyforge_project = "bogus" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.add_dependency 'dependor', '>= 0.0.4' s.add_development_dependency 'rake' s.add_development_dependency 'rspec' s.add_development_dependency 'cucumber' s.add_development_dependency 'aruba' s.add_development_dependency 'guard' s.add_development_dependency 'guard-rspec' s.add_development_dependency 'guard-cucumber' s.add_development_dependency 'guard-ctags-bundler' s.add_development_dependency 'growl' s.add_development_dependency 'libnotify' s.add_development_dependency 'relish' s.add_development_dependency 'coveralls' s.add_development_dependency 'wwtd' s.add_development_dependency 'activerecord', '>= 3', '< 5' s.add_development_dependency 'activerecord-nulldb-adapter' s.add_development_dependency 'minitest', '>= 4.7' s.add_development_dependency "rb-readline", "~> 0.5.0" # fix for the can't modify string issue end bogus-0.1.6/spec/0000755000004100000410000000000012454377662013637 5ustar www-datawww-databogus-0.1.6/spec/spec_helper.rb0000644000004100000410000000130512454377662016454 0ustar www-datawww-datarequire 'simplecov' begin require "coveralls" SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter] rescue LoadError warn "warning: coveralls gem not found; skipping Coveralls" SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter end SimpleCov.start do add_filter "/spec/" end require 'bogus' require 'dependor/rspec' require_relative 'support/sample_fake' require_relative 'support/fake_creator_of_fakes' require_relative 'support/matchers' require_relative 'support/shared_examples_for_keyword_arguments' require_relative 'support/ruby_features' RSpec.configure do |config| config.mock_with :rspec end bogus-0.1.6/spec/bogus/0000755000004100000410000000000012454377662014756 5ustar www-datawww-databogus-0.1.6/spec/bogus/bugs/0000755000004100000410000000000012454377662015716 5ustar www-datawww-databogus-0.1.6/spec/bogus/bugs/rbx_jruby_stub_on_class_spec.rb0000644000004100000410000000161612454377662024205 0ustar www-datawww-datarequire 'spec_helper' class ExampleForRbxJRubyBug def self.bar(argument) argument end def self.foo(argument) argument end def initialize(*args) args end end describe ExampleForRbxJRubyBug do before do extend Bogus::MockingDSL end context '.bar' do specify 'stubbing class twice in example' do stub(ExampleForRbxJRubyBug).bar('same_argument') stub(ExampleForRbxJRubyBug).bar('same_argument') end end context '.foo' do specify 'stubbing class once in example' do stub(ExampleForRbxJRubyBug).foo('same_argument') end specify 'stubbing class once in another example' do stub(ExampleForRbxJRubyBug).foo('same_argument') end end context '.new' do before { stub(ExampleForRbxJRubyBug).new(any_args) } specify { ExampleForRbxJRubyBug.new(1, 2, 3) } specify { ExampleForRbxJRubyBug.new(1, 2, 3) } end end bogus-0.1.6/spec/bogus/bugs/rbx_instance_eval_bug_spec.rb0000644000004100000410000000103112454377662023573 0ustar www-datawww-datarequire 'spec_helper' describe Bogus do class SampleForRbxInstanceEval < BasicObject def x 3 end end it "doesn't break #instance_eval on RBX" do result = SampleForRbxInstanceEval.new.instance_eval{x} expect(result).to eq(3) end it "does not break === with the monkey patch" do expect(SampleForRbxInstanceEval === SampleForRbxInstanceEval.new).to be(true) expect(BasicObject === SampleForRbxInstanceEval.new).to be(true) expect(Bogus === SampleForRbxInstanceEval.new).to be(false) end end bogus-0.1.6/spec/bogus/contracts/0000755000004100000410000000000012454377662016756 5ustar www-datawww-databogus-0.1.6/spec/bogus/contracts/interactions_repository_spec.rb0000644000004100000410000000574312454377662025327 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::InteractionsRepository do let(:interactions_repository) { Bogus::InteractionsRepository.new } def recorded?(fake_name, method, *args) interactions_repository.recorded?(fake_name, Bogus::Interaction.new(method, args)) end it "considers the interaction recorded if it was recorded previously" do interactions_repository.record(:foo, :bar, 1, 2, 3) expect(recorded?(:foo, :bar, 1, 2, 3)).to be(true) end it "considers the interaction recorded if it returned the same value as passed block" do interactions_repository.record(:foo, :bar) { "a result" } interaction = Bogus::Interaction.new(:bar, []) { "a result" } expect(interactions_repository.recorded?(:foo, interaction)).to be(true) end it "does not consider any interactions recorded prior to any recordings" do expect(recorded?(:foo, :bar, 1)).to be(false) end it "does not consider the interaction recorded with a different fake name" do interactions_repository.record(:baz, :bar, 1) expect(recorded?(:foo, :bar, 1)).to be(false) end it "does not consider the interaction recorded with a different method name" do interactions_repository.record(:foo, :baz, 1) expect(recorded?(:foo, :bar, 1)).to be(false) end it "does not consider the interaction recorded with different method arguments" do interactions_repository.record(:foo, :bar, 1, 2) expect(recorded?(:foo, :bar, 1)).to be(false) end it "returns a list of interactions for given fake" do interactions_repository.record(:foo, :bar, 1, 2) interactions = interactions_repository.for_fake(:foo) expect(interactions.size).to eq(1) expect(interactions.first.method).to eq :bar expect(interactions.first.args).to eq [1, 2] end it "ignores arguments if the checked interaction has any_args" do interactions_repository.record(:foo, :bar, 1) expect(recorded?(:foo, :bar, Bogus::AnyArgs)).to be(true) end it "takes method name into account when matching interaction with wildcard arguments" do interactions_repository.record(:foo, :baz, 1) expect(recorded?(:foo, :bar, Bogus::AnyArgs)).to be(false) end it "ignores arguments if the recorded interaction was recorded with wildcard argument" do interactions_repository.record(:foo, :bar, 1, 2) expect(recorded?(:foo, :bar, 1, Bogus::Anything)).to be(true) end it "takes other arguments into account when matching interactions with wildcards" do interactions_repository.record(:foo, :bar, 1, 2) expect(recorded?(:foo, :bar, 2, Bogus::Anything)).to be(false) end it "ignores arguments if the checked interaction has any_args" do interactions_repository.record(:foo, :bar, 1, 2) expect(recorded?(:foo, :bar, 1, Bogus::Anything)).to be(true) end it "takes method name into account when matching interaction with wildcard arguments" do interactions_repository.record(:foo, :baz, 1, 2) expect(recorded?(:foo, :bar, 1, Bogus::Anything)).to be(false) end end bogus-0.1.6/spec/bogus/contracts/verifies_contracts_spec.rb0000644000004100000410000000372112454377662024214 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::VerifiesContracts do let(:real_interactions) { double } let(:doubled_interactions) { double } let(:verifies_contracts) { isolate(Bogus::VerifiesContracts) } let(:matched_interaction) { interaction("matched") } it "fails unmatched calls" do first_interaction = interaction("first") second_interaction = interaction("second") other_interaction = interaction("other") allow(doubled_interactions).to receive(:for_fake).with(:fake_name){[first_interaction, matched_interaction, second_interaction]} allow(real_interactions).to receive(:for_fake).with(:fake_name){[matched_interaction, other_interaction]} allow(real_interactions).to receive(:recorded?).with(:fake_name, first_interaction) { false } allow(real_interactions).to receive(:recorded?).with(:fake_name, second_interaction) { false } allow(real_interactions).to receive(:recorded?).with(:fake_name, matched_interaction) { true } expect_verify_to_raise_error_with_interactions(:fake_name, [first_interaction, second_interaction], [matched_interaction, other_interaction]) end it "passes with all calls matched" do allow(doubled_interactions).to receive(:for_fake).with(:fake_name) { [matched_interaction] } allow(real_interactions).to receive(:recorded?).with(:fake_name, matched_interaction) { true } expect { verifies_contracts.verify(:fake_name) }.not_to raise_error end def expect_verify_to_raise_error_with_interactions(name, missed, real) verifies_contracts.verify(name) fail rescue Bogus::ContractNotFulfilled => contract_error expect(contract_error.fake_name).to eq name expect(contract_error.missed_interactions).to eq missed expect(contract_error.actual_interactions).to eq real end def interaction(method) Bogus::Interaction.new(method, [:foo, :bar]) { "return value" } end end bogus-0.1.6/spec/bogus/contracts/records_double_interactions_spec.rb0000644000004100000410000000166712454377662026104 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::RecordsDoubleInteractions do let(:fake_registry) { double } let(:doubled_interactions) { double } let(:object) { Object.new } let(:records_double_interactions) { isolate(Bogus::RecordsDoubleInteractions) } it "records the call in double interaction repository" do allow(fake_registry).to receive(:name).with(object) { :object_name } allow(doubled_interactions).to receive(:record) records_double_interactions.record(object, :method_name, [:foo, 1]) expect(doubled_interactions).to have_received(:record).with(:object_name, :method_name, :foo, 1) end it "does not record the interaction if object is not a fake" do allow(fake_registry).to receive(:name).with(object) { nil } allow(doubled_interactions).to receive(:record) records_double_interactions.record(object, :method_name, [:foo, 1]) expect(doubled_interactions).not_to have_received(:record) end end bogus-0.1.6/spec/bogus/contracts/adds_contract_verification_spec.rb0000644000004100000410000000655012454377662025675 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::AddsContractVerification do class FakeSyntax attr_accessor :described_class def initialize(described_class = nil) @described_class = described_class end def before(&block) @before = block end def run_before instance_eval(&@before) end def after(&block) @after = block end def run_after instance_eval(&@after) end def after_suite(&block) @after_suite = block end def run_after_suite instance_eval(&@after_suite) end end def self.it_verifies_contract_after_suite it "verifies the contract in after_suite" do syntax.run_after_suite expect(verifies_contracts).to have_received(:verify).with(:some_fake) end end class SomeClass end class ClassGuessedFromFakeName end let(:overwritten_class) { :the_overwritten_class } let(:adds_recording) { double } let(:verifies_contracts) { double } let(:converts_name_to_class) { double } let(:syntax) { FakeSyntax.new(described_class) } let(:adds_contract_verification) { isolate(Bogus::AddsContractVerification) } before do allow(adds_recording).to receive(:add) { overwritten_class } allow(verifies_contracts).to receive(:verify) allow(converts_name_to_class).to receive(:convert) { ClassGuessedFromFakeName } end context "with described_class" do let(:described_class) { SomeClass } before do adds_contract_verification.add(:some_fake) end it "overwrites described_class in before" do syntax.run_before expect(syntax.described_class).to eq overwritten_class end it "resets described_class in after" do syntax.run_before syntax.run_after expect(syntax.described_class).to eq SomeClass end it_verifies_contract_after_suite it "adds recording to described_class" do syntax.run_before expect(adds_recording).to have_received(:add).with(:some_fake, SomeClass) end end class ClassToOverwrite end context "with a custom class to overwrite" do let(:described_class) { SomeClass } before do adds_contract_verification.add(:some_fake) { ClassToOverwrite } end it "does not overwrite described_class in before" do syntax.run_before expect(syntax.described_class).to eq SomeClass end it "does not change described_class in after" do syntax.run_before syntax.run_after expect(syntax.described_class).to eq SomeClass end it_verifies_contract_after_suite it "adds recording to custom class" do syntax.run_before expect(adds_recording).to have_received(:add).with(:some_fake, ClassToOverwrite) end end context "with no custom or described class" do let(:described_class) { nil } before do adds_contract_verification.add(:some_fake) end it "does not overwrite described_class in before" do syntax.run_before expect(syntax.described_class).to be_nil end it "does not change described_class in after" do syntax.run_before syntax.run_after expect(syntax.described_class).to be_nil end it_verifies_contract_after_suite it "adds recording to class based on fake name" do syntax.run_before expect(adds_recording).to have_received(:add).with(:some_fake, ClassGuessedFromFakeName) end end end bogus-0.1.6/spec/bogus/contracts/proxy_class_spec.rb0000644000004100000410000000521512454377662022666 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::ProxyClass do module SampleModule class GrandLibrary SAMPLE_CONSTANT = "foo" def checkout(book, user) :checkouted end def self.find_by_address(address) :the_library end def self.find_by_isbn(isbn) raise StandardError end end end let(:proxy_class) { Bogus::ProxyClass.new(:fake_name, SampleModule::GrandLibrary, create_recording_proxy) } let(:create_recording_proxy) do lambda {|instance, fake_name| Bogus::RecordingProxy.new(instance, fake_name, interactions_repository) } end let(:interactions_repository) { FakeRepository.new } it "returns the proxy" do expect(proxy_class.new.checkout("Moby Dick", "Bob")).to eq :checkouted end it "records interactions with created objects" do proxy_class.new.checkout("Moby Dick", "Bob") expect(interactions_repository).to have_recorded(:fake_name, :checkout, "Moby Dick", "Bob") end it "responds to every method that the original class responds to" do expect(proxy_class).to respond_to(:find_by_address) end it "delegates interactions with the proxy class to wrapped class" do expect(proxy_class.find_by_address("some address")).to eq :the_library end it "records interactions with the proxy class" do proxy_class.find_by_address("some address") expect(interactions_repository).to have_recorded(:fake_name, :find_by_address, "some address") end it "records return values" do proxy_class.find_by_address("some address") expect(interactions_repository.return_value(:fake_name, :find_by_address, "some address")).to eq :the_library end it "re-raises exceptions" do expect { proxy_class.find_by_isbn("some isbn") }.to raise_error(StandardError) end it "records raised exceptions" do proxy_class.find_by_isbn("some isbn") rescue nil expect { interactions_repository.return_value(:fake_name, :find_by_isbn, "some isbn") }.to raise_error(StandardError) end it "allows accessing the constants defined on proxied class" do expect(proxy_class::SAMPLE_CONSTANT).to eq "foo" end class FakeRepository def initialize @recordings = [] end def record(fake_name, method, *args, &block) @recordings << [fake_name, method, args, block] end def has_recorded?(fake_name, method, *args) !!find(fake_name, method, *args) end def return_value(fake_name, method, *args) find(fake_name, method, *args).last.call end def find(fake_name, method, *args) @recordings.find do |f, m, a, b| [f, m, a] == [fake_name, method, args] end end end end bogus-0.1.6/spec/bogus/contracts/adds_recording_spec.rb0000644000004100000410000000216412454377662023267 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::AddsRecording do module SampleModule class Library end class OtherClass end end let(:create_proxy_class) { double } let(:overwrites_classes) { double } let(:overwritten_classes) { double } let(:adds_recording) { isolate(Bogus::AddsRecording) } before do allow(create_proxy_class).to receive(:call) { Object } allow(overwrites_classes).to receive(:overwrite) allow(overwritten_classes).to receive(:add) end before do adds_recording.add(:library, SampleModule::Library) end it "creates the proxy" do expect(create_proxy_class).to have_received(:call).with(:library, SampleModule::Library) end it "swaps the classes" do expect(overwrites_classes).to have_received(:overwrite).with('SampleModule::Library', Object) end it "records the overwritten class, so that it can be later restored" do expect(overwritten_classes).to have_received(:add).with("SampleModule::Library", SampleModule::Library) end it "returns the proxy class" do expect(adds_recording.add(:library, SampleModule::Library)).to eq Object end end bogus-0.1.6/spec/bogus/clean_ruby_spec.rb0000644000004100000410000000040012454377662020432 0ustar www-datawww-datarequire 'spec_helper' describe "Ruby syntax" do it "is clean" do expect(bogus_warnings).to eq([]) end def bogus_warnings warnings.select { |w| w =~ %r{lib/bogus} } end def warnings `ruby -w lib/bogus.rb 2>&1`.split("\n") end end bogus-0.1.6/spec/bogus/ruby_2_support_spec.rb0000644000004100000410000000224612454377662021317 0ustar www-datawww-datarequire 'spec_helper' if RubyFeatures.keyword_arguments? describe "Ruby 2.0 keyword arguments" do class ExampleForKeywordArgs eval "def foo(x: 1); end" eval "def bar(x: 1, **rest); end" end before do extend Bogus::MockingDSL end context "with regular objects" do subject { ExampleForKeywordArgs.new } it "allows calling the method without the optional keyword args" do stub(subject).foo(any_args) subject.foo expect(subject).to have_received.foo end include_examples "stubbing methods with keyword arguments" include_examples "stubbing methods with double splat" end context "with fakes" do subject { fake(:example_for_keyword_args) } it "allows spying without stubbing" do subject.foo(x: "test") expect(subject).to have_received.foo(x: "test") end it "allows calling the method without the optional keyword args" do subject.foo expect(subject).to have_received.foo end include_examples "stubbing methods with keyword arguments" include_examples "stubbing methods with double splat" end end end bogus-0.1.6/spec/bogus/configuration_spec.rb0000644000004100000410000000060512454377662021165 0ustar www-datawww-datarequire_relative '../spec_helper' describe Bogus::Configuration do before { Bogus.reset! } it "stores the modules to be searched" do Bogus.configure do |c| c.search_modules << String end expect(Bogus.config.search_modules).to eq [Object, String] end it "defaults search_modules to [Object]" do expect(Bogus.config.search_modules).to eq [Object] end end bogus-0.1.6/spec/bogus/ruby_2_1_support_spec.rb0000644000004100000410000000210212454377662021526 0ustar www-datawww-datarequire 'spec_helper' if RubyFeatures.required_keyword_arguments? describe "Ruby 2.1 required keyword arguments" do class ExampleForRequiredKeywordArgs eval "def foo(x:); end" eval "def bar(x:, **rest); end" end before do extend Bogus::MockingDSL end context "with regular objects" do subject { ExampleForRequiredKeywordArgs.new } it "does not allow calling the method without all required arguments" do stub(subject).foo(any_args) { :hello } expect{ subject.foo }.to raise_error(ArgumentError) end include_examples "stubbing methods with keyword arguments" include_examples "stubbing methods with double splat" end context "with fakes" do subject { fake(:example_for_required_keyword_args) } it "allows spying without stubbing" do subject.foo(x: "hello") expect(subject).to have_received.foo(x: "hello") end include_examples "stubbing methods with keyword arguments" include_examples "stubbing methods with double splat" end end end bogus-0.1.6/spec/bogus/fakes/0000755000004100000410000000000012454377662016047 5ustar www-datawww-databogus-0.1.6/spec/bogus/fakes/overwrites_classes_spec.rb0000644000004100000410000000117012454377662023333 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::OverwritesClasses do module SampleOuterModule module SampleModule class SampleClass end end end let(:new_class) { Class.new } let(:overwrites_classes) { Bogus::OverwritesClasses.new } it "overwrites nested classes" do overwrites_classes.overwrite('SampleOuterModule::SampleModule::SampleClass', new_class) expect(SampleOuterModule::SampleModule::SampleClass).to equal(new_class) end it "overwrites top level classes" do overwrites_classes.overwrite('SampleOuterModule', new_class) expect(SampleOuterModule).to equal(new_class) end end bogus-0.1.6/spec/bogus/fakes/creates_fakes_spec.rb0000644000004100000410000000407512454377662022213 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::CreatesFakes do let(:fake_class) { double } let(:fake_instance) { double } let(:converts_name_to_class) { double } let(:copies_classes) { double } let(:makes_ducks) { double } let(:creates_fakes) { isolate(Bogus::CreatesFakes) } module Foo end module Bar end before { allow(fake_class).to receive(:__create__){fake_instance} } context "without block" do before do expect(converts_name_to_class).to receive(:convert).with(:foo) { Foo } expect(copies_classes).to receive(:copy).with(Foo) { fake_class } end it "creates a new instance of copied class by default" do expect(creates_fakes.create(:foo)).to eq fake_instance end it "creates a new instance of copied class if called with as: :instance" do expect(creates_fakes.create(:foo, as: :instance)).to eq fake_instance end it "copies class but does not create an instance if called with as: :class" do expect(creates_fakes.create(:foo, as: :class)).to eq fake_class end it "raises an error if the as mode is not known" do expect do creates_fakes.create(:foo, as: :something) end.to raise_error(Bogus::CreatesFakes::UnknownMode) end end context "with block" do before do allow(converts_name_to_class).to receive(:convert) expect(copies_classes).to receive(:copy).with(Bar) { fake_class } end it "uses the class provided" do expect(creates_fakes.create(:foo){Bar}).to eq fake_instance end it "does not convert the class name" do creates_fakes.create(:foo) { Bar} expect(converts_name_to_class).not_to have_received(:convert) end end module FooBarDuck end context "with multiple classes" do it "creates a duck type out of those classes and fakes it" do allow(makes_ducks).to receive(:make).with(Foo, Bar) { FooBarDuck } allow(copies_classes).to receive(:copy).with(FooBarDuck) { :the_fake } fake = creates_fakes.create(:role, as: :class) { [Foo, Bar] } expect(fake).to eq :the_fake end end end bogus-0.1.6/spec/bogus/fakes/makes_substitute_methods_spec.rb0000644000004100000410000000127112454377662024525 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe MakesSubstituteMethods do class SampleForCopyingMethods def self.foo(name, value = "hello", *rest, &block) "this is the method body" end end let(:method_stringifier) { isolate(MethodStringifier) } let(:makes_substitute_methods) { isolate(MakesSubstituteMethods) } it "makes a copy of the method with its params and adds recording" do copy = makes_substitute_methods.stringify(SampleForCopyingMethods.method(:foo)) expect(copy).to eq <<-EOF def foo(name, value = Bogus::DefaultValue, *rest, &block) __record__(:foo, name, value, *rest, &block) end EOF end end end bogus-0.1.6/spec/bogus/fakes/fakes_classes_spec.rb0000644000004100000410000000300112454377662022206 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::FakesClasses do let(:creates_fakes_with_stubbed_methods) { FakeCreatorOfFakes.new } let(:overwrites_classes) { double } let(:overwritten_classes) { double } let(:fakes_classes) { isolate(Bogus::FakesClasses) } module Samples class WillBeOverwritten end end before do allow(overwrites_classes).to receive(:overwrite) allow(overwritten_classes).to receive(:add) end it "creates a fake named after the class" do fakes_classes.fake(Samples::WillBeOverwritten, foo: "bar") expect(creates_fakes_with_stubbed_methods).to have_created(:will_be_overwritten, {as: :class, foo: "bar"}, Samples::WillBeOverwritten) end it "overwrites the class with the fake" do fake = [:will_be_overwritten, {as: :class}, Samples::WillBeOverwritten] fakes_classes.fake(Samples::WillBeOverwritten) expect(overwrites_classes).to have_received(:overwrite).with("Samples::WillBeOverwritten", fake) end it "stores the overwritten class so that it can be replaced back later" do fakes_classes.fake(Samples::WillBeOverwritten) expect(overwritten_classes).to have_received(:add).with("Samples::WillBeOverwritten", Samples::WillBeOverwritten) end it "uses the passed fake name if provided" do fakes_classes.fake(Samples::WillBeOverwritten, fake_name: :foo_bar) expect(creates_fakes_with_stubbed_methods).to have_created(:foo_bar, {as: :class}, Samples::WillBeOverwritten) end end bogus-0.1.6/spec/bogus/fakes/copies_classes_spec.rb0000644000004100000410000001037312454377662022411 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::CopiesClasses do module SampleMethods def foo end def bar(x) end def baz(x, *y) end def bam(opts = {}) end def baa(x, &block) end end shared_examples_for 'the copied class' do it "copies methods with no arguments" do expect(subject).to respond_to(:foo) subject.foo end it "copies methods with explicit arguments" do expect(subject).to respond_to(:bar) expect(subject.method(:bar).arity).to eq 1 subject.bar('hello') end it "copies methods with variable arguments" do expect(subject).to respond_to(:baz) subject.baz('hello', 'foo', 'bar', 'baz') end it "copies methods with default arguments" do expect(subject).to respond_to(:bam) subject.bam subject.bam(hello: 'world') end it "copies methods with block arguments" do expect(subject).to respond_to(:baa) subject.baa('hello') subject.baa('hello') {} end end let(:copies_classes) { Bogus.inject.copies_classes } let(:fake_class) { copies_classes.copy(klass) } let(:fake) { fake_class.new } class FooWithInstanceMethods CONST = "the const" include SampleMethods end context "nested constants" do let(:klass) { FooWithInstanceMethods } it "does not overwrite nested constants" do expect(fake_class::CONST).to eq "the const" end end context "instance methods" do let(:klass) { FooWithInstanceMethods } subject{ fake } it_behaves_like 'the copied class' end context "constructors" do let(:klass) { Class.new do def initialize(hello) end def foo end end } it "adds a no-arg constructor" do instance = fake_class.__create__ expect(instance).to respond_to(:foo) end it "adds a constructor that allows passing the correct number of arguments" do instance = fake_class.new('hello') expect(instance).to respond_to(:foo) end end class ClassWithClassMethods extend SampleMethods end context "class methods" do let(:klass) { ClassWithClassMethods } subject{ fake_class } it_behaves_like 'the copied class' end context "identification" do module SomeModule class SomeClass end end let(:klass) { SomeModule::SomeClass } it "should copy the class name" do expect(fake.class.name).to eq 'SomeModule::SomeClass' end it "should override kind_of?" do expect(fake.kind_of?(SomeModule::SomeClass)).to be(true) end it "should override instance_of?" do expect(fake.instance_of?(SomeModule::SomeClass)).to be(true) end it "should override is_a?" do expect(fake.is_a?(SomeModule::SomeClass)).to be(true) end it "should include class name in the output of fake's class #to_s" do expect(fake.class.to_s).to include(klass.name) end it "should include class name in the output of fake's #to_s" do expect(fake.to_s).to include(klass.name) end it 'should override ===' do expect(SomeModule::SomeClass === fake).to be(true) end end shared_examples_for 'spying' do def should_record(method, *args) expect(subject).to receive(:__record__).with(method, *args) subject.send(method, *args) end it "records method calls with no arguments" do should_record(:foo) end it "records method calls with explicit arguments" do should_record(:bar, 'hello') end it "records method calls with variable arguments" do should_record(:baz, 'hello', 'foo', 'bar', 'baz') end it "records method calls with default arguments" do should_record(:bam, hello: 'world') end end context "spying on an instance" do let(:klass) { FooWithInstanceMethods } subject{ fake } include_examples 'spying' end context "spying on copied class" do let(:klass) { ClassWithClassMethods } subject { fake_class } include_examples 'spying' end class SomeModel def save(*) # ignores arguments end end context "copying classes with methods with nameless parameters" do let(:klass) { SomeModel } it "copies those methods" do expect(fake).to respond_to(:save) end end end bogus-0.1.6/spec/bogus/fakes/instance_methods_spec.rb0000644000004100000410000000162712454377662022743 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe InstanceMethods do class SampleClass def foo(bar) end def hello end def self.bar(bam) end end let(:instance_methods) { InstanceMethods.new(SampleClass) } it "lists the instance methods" do expect(instance_methods.all).to match_array([:foo, :hello]) end it "returns the instance methods by name" do expect(instance_methods.get(:foo)).to eq( SampleClass.instance_method(:foo)) end it "removes methods by name" do instance_methods.remove(:hello) expect(SampleClass.new).to_not respond_to(:hello) end it "defines instance methods" do instance_methods.define <<-EOF def greet(name) return "Hello, " + name + "!" end EOF instance = SampleClass.new expect(instance.greet("Joe")).to eq "Hello, Joe!" end end end bogus-0.1.6/spec/bogus/fakes/stubbing_new_method_on_fake_class_spec.rb0000644000004100000410000000111012454377662026274 0ustar www-datawww-datarequire 'spec_helper' describe "Stubbing .new on fake class" do class ExampleForStubbingNew end before do extend Bogus::MockingDSL end it "allows stubbing new on a class" do fake_class = fake(ExampleForStubbingNew, as: :class) stub(fake_class).new { :stubbed_value } instance = fake_class.new expect(instance).to eq(:stubbed_value) end it "returns fake instances when nothing is stubbed" do fake_class = fake(ExampleForStubbingNew, as: :class) instance = fake_class.new expect(instance).to be_an_instance_of(fake_class) end end bogus-0.1.6/spec/bogus/fakes/fake_registry_spec.rb0000644000004100000410000000077112454377662022251 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::FakeRegistry do let(:fake_registry) { Bogus::FakeRegistry.new } it "knows the fake's names" do object = Object.new fake_registry.store(:name, object) expect(fake_registry.name(object)).to eq :name end it "returns name based on object identity" do example = Struct.new(:id) object = example.new(1) duplicate = example.new(1) fake_registry.store(:object, object) expect(fake_registry.name(duplicate)).to be_nil end end bogus-0.1.6/spec/bogus/fakes/converts_name_to_class_spec.rb0000644000004100000410000000214312454377662024140 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::ConvertsNameToClass do FooBarBaz = Class.new module Foo FooBarBaz = Class.new end module Bar FooBarBaz = Class.new Bam = Class.new end it "finds classes in golbal namespace by default" do converts_name_to_class = Bogus::ConvertsNameToClass.new(Bogus.config.search_modules) expect(converts_name_to_class.convert(:foo_bar_baz)).to eq FooBarBaz end it "looks in the modules in the specified order" do converts_name_to_class = Bogus::ConvertsNameToClass.new([Foo, Bar]) expect(converts_name_to_class.convert(:foo_bar_baz)).to eq Foo::FooBarBaz end it "looks in the next module on the list if the first does not contain the class" do converts_name_to_class = Bogus::ConvertsNameToClass.new([Foo, Bar]) expect(converts_name_to_class.convert(:bam)).to eq Bar::Bam end it "raises an error if it can't find the class" do converts_name_to_class = Bogus::ConvertsNameToClass.new([Foo]) expect do converts_name_to_class.convert(:bam) end.to raise_error(Bogus::ConvertsNameToClass::CanNotFindClass) end end bogus-0.1.6/spec/bogus/fakes/resets_overwritten_classes_spec.rb0000644000004100000410000000147512454377662025107 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::ResetsOverwrittenClasses do let(:classes) { [['Foo', :foo], ['Bar', :bar]] } let(:overwritten_classes) { double } let(:overwrites_classes) { double } let(:resets_overwritten_classes) { isolate(Bogus::ResetsOverwrittenClasses) } before do allow(overwritten_classes).to receive(:classes) { classes } allow(overwritten_classes).to receive(:clear) allow(overwrites_classes).to receive(:overwrite) resets_overwritten_classes.reset end it "overwrites back all of the overwritten classes" do expect(overwrites_classes).to have_received(:overwrite).with('Foo', :foo) expect(overwrites_classes).to have_received(:overwrite).with('Bar', :bar) end it "clears the overwritten classes" do expect(overwritten_classes).to have_received(:clear) end end bogus-0.1.6/spec/bogus/fakes/fake_configuration_spec.rb0000644000004100000410000000437712454377662023256 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::FakeConfiguration do let(:config) { Bogus::FakeConfiguration.new } it "does not contain not configured fakes" do expect(config.include?(:foo)).to be(false) end def class_block(name) config.get(name).class_block end def opts(name) config.get(name).opts end def stubs(name) config.get(name).stubs end it "contains configured fakes" do config.evaluate do fake(:foo, as: :class, class: proc{Samples::Foo}) do bar "the bar" end end expect(config.include?(:foo)).to be(true) expect(config.include?(:bar)).to be(false) end it "returns the configuration for a fake" do config.evaluate do fake(:foo, as: :class, class: proc{Samples::Foo}) do bar "the bar" end end expect(opts(:foo)).to eq ({ as: :class} ) expect(stubs(:foo)).to eq ({ bar: "the bar"} ) expect(class_block(:foo).call).to eq Samples::Foo end context "with no class" do it "does not return any class block" do config.evaluate do fake(:foo, as: :class) { bar "bar" } end expect(opts(:foo)).to eq ({ as: :class} ) expect(stubs(:foo)).to eq ({ bar: "bar"} ) expect(class_block(:foo)).to be_nil end end context "with no options" do it "does not return any options" do config.evaluate do fake(:foo) { bar "bar" } end expect(opts(:foo)).to eq ({ } ) expect(stubs(:foo)).to eq ({ bar: "bar"} ) expect(class_block(:foo)).to be_nil end end context "with block return value definitions" do it "returns the values, not blocks" do config.evaluate do fake(:foo) { bar {"bar"} } end expect(stubs(:foo)[:bar].call).to eq "bar" end it "does not evaluate the blocks when getting, nor when setting" do config.evaluate do fake(:foo) { bar { raise "gotcha" } } end block = stubs(:foo)[:bar] expect{ block.call }.to raise_error end end context "witn no stubs block" do it "returns the options" do config.evaluate do fake(:foo, as: :class) end expect(opts(:foo)).to eq ({ as: :class} ) expect(stubs(:foo)).to eq ({ } ) expect(class_block(:foo)).to be_nil end end end bogus-0.1.6/spec/bogus/fakes/registers_created_fakes_spec.rb0000644000004100000410000000173712454377662024265 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::RegistersCreatedFakes do let(:fake_registry) { double } let(:creates_fakes) { double } let(:double_tracker) { double } let(:registers_created_fakes) { isolate(Bogus::RegistersCreatedFakes) } before do allow(fake_registry).to receive(:store) allow(creates_fakes).to receive(:create) { :the_fake } allow(double_tracker).to receive(:track).with(:the_fake) end it "registers the fakes created by creates_fakes" do registers_created_fakes.create(:foo, as: :instance) { Object } expect(fake_registry).to have_received(:store).with(:foo, :the_fake) end it "tracks the created fakes for purposes of mock expectations" do registers_created_fakes.create(:foo, as: :instance) { Object } expect(double_tracker).to have_received(:track).with(:the_fake) end it "returns the created fake" do fake = registers_created_fakes.create(:foo, as: :instance) { Object } expect(fake).to eq :the_fake end end bogus-0.1.6/spec/bogus/fakes/faking_factories_spec.rb0000644000004100000410000000307612454377662022712 0ustar www-datawww-datarequire 'spec_helper' describe "Faking Factories" do before do extend Bogus::MockingDSL end class ExampleFactory def initialize(model_class) @model_class = model_class end def create(y) @model_class.new(1, y) end end class ExampleModel1 def initialize(x, y) end end it "allows spying on factory classes" do model_class = fake(:example_model, as: :class) { ExampleModel1 } factory = ExampleFactory.new(model_class) factory.create(2) expect(model_class).to have_received.new(1, 2) end class ExampleModel2 def initialize(x, y, z) end end it "retains the arity safety" do model_class = fake(:example_model, as: :class) { ExampleModel2 } factory = ExampleFactory.new(model_class) expect { factory.create(2) }.to raise_error(ArgumentError) end class ExampleModel3 end it "works with classes with no explicit constructor" do model_class = fake(:example_model, as: :class) { ExampleModel3 } model = model_class.new expect(model_class).to have_received.new end class ExampleModel4 def initialize(y) end def foo(x) end end it "allows creating the model instances as usual" do model = fake(:example_model) { ExampleModel4 } model.foo(1) expect(model).to have_received.foo(1) end module ExampleModel5 def self.foo(x) end end it "allows creating fakes of modules as usual" do model = fake(:example_model, as: :class) { ExampleModel5 } model.foo(1) expect(model).to have_received.foo(1) end end bogus-0.1.6/spec/bogus/fakes/fake_spec.rb0000644000004100000410000000020612454377662020312 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::Fake do it 'has a class name' do expect(Bogus::Fake.name).to eq "Bogus::Fake" end end bogus-0.1.6/spec/bogus/fakes/overwriten_classes_spec.rb0000644000004100000410000000134012454377662023325 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::OverwrittenClasses do let(:overwritten_classes) { Bogus::OverwrittenClasses.new } let(:klass) { Class.new } it "adds classes" do overwritten_classes.add("Foo::Bar", klass) overwritten_classes.add("Baz::Bam", klass) expect(overwritten_classes.classes).to eq [["Foo::Bar", klass], ["Baz::Bam", klass]] end it "clears overwritten classes" do overwritten_classes.add("Foo::Bar", klass) overwritten_classes.add("Baz::Bam", klass) overwritten_classes.clear expect(overwritten_classes.classes).to eq [] end it "returns an empty array with no classes" do expect(overwritten_classes.classes).to eq [] end end bogus-0.1.6/spec/bogus/fakes/creates_fakes_with_stubbed_methods_spec.rb0000644000004100000410000000753212454377662026502 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe CreatesFakesWithStubbedMethods do let(:creates_fakes) { FakeCreatorOfFakes.new } let(:fake_configuration) { double } let(:responds_to_everything) { double } let(:multi_stubber) { double } let(:creates_anonymous_stubs) { isolate(CreatesFakesWithStubbedMethods) } before do allow(fake_configuration).to receive(:include?) { false } allow(multi_stubber).to receive(:stub_all) { :stubbed_object } end context "given symbol as first parameter" do let(:fake) { [:foo, {as: :class}, "something"] } before do creates_anonymous_stubs.create(:foo, bar: 1, as: :class) { "something" } end it "creates fakes" do expect(creates_fakes).to have_created(:foo, {as: :class}, "something") end it "stubs all the given methods" do expect(multi_stubber).to have_received(:stub_all).with(fake, bar: 1) end end context "given hash as first parameter" do before do creates_anonymous_stubs.create(bar: 1) end it "does not create fakes" do expect(creates_fakes.fakes).to eq [] end it "stubs all the given methods" do expect(multi_stubber).to have_received(:stub_all).with(responds_to_everything, bar: 1) end end context "given symbol as only parameter" do let(:fake) { [:foo, {}, "something"] } before do creates_anonymous_stubs.create(:foo) { "something" } end it "creates fakes" do expect(creates_fakes).to have_created(:foo, {}, "something") end it "stubs all the given methods" do expect(multi_stubber).to have_received(:stub_all).with(fake, {}) end end context "with no parameters" do before do creates_anonymous_stubs.create end it "does not create fakes" do expect(creates_fakes.fakes).to eq [] end it "stubs all the given methods" do expect(multi_stubber).to have_received(:stub_all).with(responds_to_everything, {}) end end context "when the fake was globally configured" do let(:fake) { [:foo, {as: :class}, "SomeClass"] } before do allow(fake_configuration).to receive(:include?).with(:foo) { true } allow(fake_configuration).to receive(:get).with(:foo) { FakeDefinition.new(opts: {as: :class}, stubs: {xyz: "abc"}, class_block: proc{"SomeClass"}) } creates_anonymous_stubs.create(:foo) end it "uses the configuration to create fake" do expect(creates_fakes.fakes).to eq [fake] expect(fake_configuration).to have_received(:include?).with(:foo) expect(fake_configuration).to have_received(:get).with(:foo) end it "stubs the methods defined in configuration" do expect(multi_stubber).to have_received(:stub_all).with(fake, xyz: "abc") end end context "overriding the global configuration" do let(:fake) { [:foo, {as: :instance}, "SomeOtherClass"] } before do allow(fake_configuration).to receive(:include?).with(:foo) { true } allow(fake_configuration).to receive(:get).with(:foo) { FakeDefinition.new(opts: {as: :class}, stubs: {a: "b", b: "c"}, class_block: proc{"SomeClass"}) } creates_anonymous_stubs.create(:foo, as: :instance, b: "d", c: "e") { "SomeOtherClass" } end it "overrides the class block and fake options" do expect(creates_fakes).to have_created(:foo, {as: :instance}, "SomeOtherClass") end it "overrides the stubbed methods" do expect(multi_stubber).to have_received(:stub_all).with(fake, a: "b", b: "d", c: "e") end end end end bogus-0.1.6/spec/bogus/fakes/frozen_fakes_spec.rb0000644000004100000410000000220212454377662022056 0ustar www-datawww-datarequire "spec_helper" describe "Frozen Fakes" do before do extend Bogus::MockingDSL end class ExampleForFreezing def foo(x) end end shared_examples_for "frozen fakes" do before { object.freeze } describe "stubbing" do it "allows stubbing" do stub(object).foo(1) { 123 } expect(object.foo(1)).to eq 123 end end describe "mocking" do it "allows mocking" do mock(object).foo(1) { 123 } expect(object.foo(1)).to eq 123 end it "allows verifying expectations" do mock(object).foo(1) { 123 } expect { Bogus.after_each_test }.to raise_error(Bogus::NotAllExpectationsSatisfied) end end describe "spying" do it "allows spying" do object.foo(1) expect(object).to have_received.foo(1) expect(object).to_not have_received.foo(2) end end end context "anonymous fakes" do let(:object) { fake } include_examples "frozen fakes" end context "named fakes" do let(:object) { fake(:example_for_freezing) } include_examples "frozen fakes" end end bogus-0.1.6/spec/bogus/fakes/class_methods_spec.rb0000644000004100000410000000203412454377662022235 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe ClassMethods do class SampleClass def foo(bar) end def self.bar(bam) end def self.hello end def self.__shadow__; end def self.__reset__; end def self.__overwrite__; end def self.__overwritten_methods__; end def self.__record__; end end let(:class_methods) { ClassMethods.new(SampleClass) } it "lists the class methods excluding the ones added by Bogus" do expect(class_methods.all).to match_array([:bar, :hello]) end it "returns the instance methods by name" do expect(class_methods.get(:bar)).to eq SampleClass.method(:bar) end it "removes methods by name" do class_methods.remove(:hello) expect(SampleClass).to_not respond_to(:hello) end it "defines instance methods" do class_methods.define <<-EOF def greet(name) return "Hello, " + name + "!" end EOF expect(SampleClass.greet("Joe")).to eq "Hello, Joe!" end end end bogus-0.1.6/spec/bogus/fakes/fake_ar_attributes_spec.rb0000644000004100000410000000264112454377662023247 0ustar www-datawww-datarequire 'spec_helper' require 'active_record' require 'nulldb' describe "Stubbing ActiveRecord::Base subclasses" do ActiveRecord::Schema.verbose = false ActiveRecord::Base.establish_connection :adapter => :nulldb ActiveRecord::Schema.define do create_table :blog_posts do |t| t.string :name t.string :author end end class BlogPost < ActiveRecord::Base def author(x) "#{x} #{self[:author]}!" end end before do extend Bogus::MockingDSL end before do Bogus.configure do |c| c.fake_ar_attributes = true end end it "makes it possible to stub active record fields" do post = fake(:blog_post, name: "hello") expect(post.name).to eq "hello" end it "works only when enabled in configuration" do Bogus.configure do |c| c.fake_ar_attributes = false end expect { fake(:blog_post, name: "hello") }.to raise_error(NameError) end it "does not overwrite existing method signatures" do post = fake(:blog_post) post.author("hello") expect(post).to have_received.author("hello") end class ExampleForActiveRecordAttributes def foo(x) end end it "does not interfere with non-ar classes" do fake = fake(:example_for_active_record_attributes) fake.foo(1) expect(fake).to have_received.foo(1) end after do Bogus.configure do |c| c.fake_ar_attributes = false end end end bogus-0.1.6/spec/bogus/fakes/base_class_identifier_spec.rb0000644000004100000410000000245512454377662023715 0ustar www-datawww-datarequire 'spec_helper' module SampleForBaseIdentifier describe Bogus::BaseClassIdentifier do module Foo def foo; end end module Bar include Foo def bar; end end module Baz def baz; end end module OtherModule end class SuperBase end class BaseClass < SuperBase include Bar def x; end end class SubClass < BaseClass include Baz def y; end end class OtherClass end class BarInstance include Bar end def self.it_returns_the_same_value_as_a_regular_instance klasses = [Foo, Bar, Baz, OtherModule, SuperBase, BaseClass, SubClass, OtherClass] klasses.each do |klass| it "returns the same for is_a?(#{klass})" do expected = instance.is_a?(klass) actual = Bogus::BaseClassIdentifier.base_class?(copied_class, klass) expect(actual).to eq expected end end end context "with copied module" do let(:copied_class) { Bar } let(:instance) { BarInstance.new } it_returns_the_same_value_as_a_regular_instance end context "with copied class" do let(:copied_class) { SubClass } let(:instance) { SubClass.new } it_returns_the_same_value_as_a_regular_instance end end end bogus-0.1.6/spec/bogus/fakes/method_copiers_spec.rb0000644000004100000410000000112712454377662022413 0ustar www-datawww-datarequire 'spec_helper' describe "Method Copiers" do shared_examples_for "method copier" do let(:klass) { Class.new } subject { isolate(described_class) } it { should respond_to(:all) } it { should respond_to(:get) } it { should respond_to(:remove) } it { should respond_to(:define) } end describe Bogus::InstanceMethods do it_behaves_like "method copier" end describe Bogus::ClassMethods do it_behaves_like "method copier" end describe Bogus::ActiveRecordAccessors do let(:instance_methods) { nil } it_behaves_like "method copier" end end bogus-0.1.6/spec/bogus/fakes/makes_ducks_spec.rb0000644000004100000410000000364312454377662021705 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe MakesDucks do class DatabaseLogger def debug(message); end def warn(*args); end def error(message, another_arg); end def log(opts = {}); end def self.foo(x, y, z = 1); end def self.bar(x, y); end end class NetworkLogger def debug(message); end def warn(*args); end def error(message); end def socket; end def self.foo(x, y, z = 1); end def self.bar(x, y, z); end def self.baz; end end let(:class_methods) do lambda{ |klass| ClassMethods.new(klass) } end let(:instance_methods) do lambda{ |klass| InstanceMethods.new(klass) } end let(:makes_ducks) { Bogus.inject.makes_ducks } let(:duck) { makes_ducks.make(DatabaseLogger, NetworkLogger) } describe "the returned class" do subject { duck } it { should respond_to(:foo) } it "should have arity -3 for foo" do expect(duck.method(:foo).arity).to eq -3 end it { should_not respond_to(:bar) } it { should_not respond_to(:baz) } end describe "instances of the returned class" do subject { duck.new } it { should respond_to(:debug) } it { should respond_to(:warn) } it { should_not respond_to(:error) } it { should_not respond_to(:socket) } end module AlwaysEnabled def enabled?; true; end extend self end module AlwaysDisabled def enabled?; false; end extend self end context "with modules" do let(:duck) { makes_ducks.make(AlwaysDisabled, AlwaysEnabled)} let(:duck_instance) do object = Object.new object.extend duck object end it "copies class methods" do expect(duck).to respond_to(:enabled?) end it "copies instance methods" do expect(duck_instance).to respond_to(:enabled?) end end end end bogus-0.1.6/spec/bogus/mocking_dsl_spec.rb0000644000004100000410000002376512454377662020623 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::MockingDSL do class ExampleFoo def foo(bar) end def hello(greeting, name) end def with_optional_args(x, y = 1) end def self.bar(baz) "Hello #{baz}" end end class Stubber extend Bogus::MockingDSL end before do Bogus.reset! end describe "#stub" do let(:baz) { ExampleFoo.new } it "allows stubbing the existing methods" do Stubber.stub(baz).foo("bar") { :return_value } expect(baz.foo("bar")).to eq :return_value end it "can stub method with any parameters" do Stubber.stub(baz).foo(Stubber.any_args) { :default_value } Stubber.stub(baz).foo("bar") { :foo_value } expect(baz.foo("a")).to eq :default_value expect(baz.foo("b")).to eq :default_value expect(baz.foo("bar")).to eq :foo_value end it "can stub method with some wildcard parameters" do Stubber.stub(baz).hello(Stubber.any_args) { :default_value } Stubber.stub(baz).hello("welcome", Stubber.anything) { :greeting_value } expect(baz.hello("hello", "adam")).to eq :default_value expect(baz.hello("welcome", "adam")).to eq :greeting_value expect(baz.hello("welcome", "rudy")).to eq :greeting_value end it "does not allow stubbing non-existent methods" do baz = ExampleFoo.new expect do Stubber.stub(baz).does_not_exist("bar") { :return_value } end.to raise_error(NameError) end it "unstubs methods after each test" do Stubber.stub(ExampleFoo).bar("John") { "something else" } Bogus.after_each_test expect(ExampleFoo.bar("John")).to eq "Hello John" end end describe "#have_received" do context "with a fake object" do let(:the_fake) { Bogus.fake_for(:example_foo) } it "allows verifying that fakes have correct interfaces" do the_fake.foo("test") expect(the_fake).to Stubber.have_received.foo("test") end it "does not allow verifying on non-existent methods" do expect { expect(the_fake).to Stubber.have_received.bar("test") }.to raise_error(NameError) end it "does not allow verifying on methods with a wrong argument count" do expect { expect(the_fake).to Stubber.have_received.foo("test", "test 2") }.to raise_error(ArgumentError) end it "allows spying on methods with optional parameters" do the_fake.with_optional_args(123) expect(the_fake).to Stubber.have_received.with_optional_args(123) end end it "can be used with plain old Ruby objects" do object = ExampleFoo.new Stubber.stub(object).foo(Stubber.any_args) object.foo('test') expect(object).to Stubber.have_received.foo("test") end it "allows spying on methods with optional parameters" do object = ExampleFoo.new Stubber.stub(object).with_optional_args(123) { 999 } expect(object.with_optional_args(123)).to eq 999 expect(object).to Stubber.have_received.with_optional_args(123) end class ClassWithMatches def matches?(something) end end it "can be used with objects that have same methods as an RSpec expectation" do fake = Bogus.fake_for(:class_with_matches) fake.matches?("foo") expect(fake).to Bogus.have_received.matches?("foo") end class PassesSelfToCollaborator def hello(example) example.foo(self) end end it "can be used with self references" do Bogus.record_calls_for(:passes_self_to_collaborator, PassesSelfToCollaborator) fake = Bogus.fake_for(:example_foo) object = PassesSelfToCollaborator.new object.hello(fake) expect(fake).to Bogus.have_received.foo(object) end end class Mocker extend Bogus::MockingDSL end describe "#mock" do let(:object) { ExampleFoo.new } let(:fake) { Bogus.fake_for(:example_foo) { ExampleFoo } } shared_examples_for "mocking dsl" do it "allows mocking on methods with optional parameters" do Mocker.mock(baz).with_optional_args(1) { :return } expect(baz.with_optional_args(1)).to eq :return expect { Bogus.after_each_test }.not_to raise_error end it "allows mocking with anything" do Mocker.mock(baz).hello(1, Bogus::Anything) { :return } expect(baz.hello(1, 2)).to eq :return expect { Bogus.after_each_test }.not_to raise_error end it "allows mocking the existing methods" do Mocker.mock(baz).foo("bar") { :return_value } expect(baz.foo("bar")).to eq :return_value expect { Bogus.after_each_test }.not_to raise_error end it "verifies that the methods mocked exist" do expect { Mocker.mock(baz).does_not_exist { "whatever" } }.to raise_error(NameError) end it "raises errors when mocks were not called" do Mocker.mock(baz).foo("bar") expect { Bogus.after_each_test }.to raise_error(Bogus::NotAllExpectationsSatisfied) end it "clears the data between tests" do Mocker.mock(baz).foo("bar") Bogus.send(:clear_expectations) expect { Bogus.after_each_test }.not_to raise_error end end class ExampleForMockingOnConstants def self.bar(foo) end def self.baz end end it "clears expected interactions from constants" do Mocker.mock(ExampleForMockingOnConstants).bar("foo") expect { Bogus.after_each_test }.to raise_error(Bogus::NotAllExpectationsSatisfied) Mocker.stub(ExampleForMockingOnConstants).baz expect { Bogus.after_each_test }.not_to raise_error end context "with fakes" do it_behaves_like "mocking dsl" do let(:baz) { fake } end end context "with regular objects" do it_behaves_like "mocking dsl" do let(:baz) { object } end end end describe "#fake" do before do extend Bogus::MockingDSL end it "creates objects that can be stubbed" do greeter = fake stub(greeter).greet("Jake") { "Hello Jake" } expect(greeter.greet("Jake")).to eq "Hello Jake" end it "creates objects that can be mocked" do greeter = fake mock(greeter).greet("Jake") { "Hello Jake" } expect(greeter.greet("Jake")).to eq "Hello Jake" end it "creates objects with some methods stubbed by default" do greeter = fake(greet: "Hello Jake") expect(greeter.greet("Jake")).to eq "Hello Jake" end it "creates objects that can be spied upon" do greeter = fake greeter.greet("Jake") expect(greeter).to have_received.greet("Jake") expect(greeter).to_not have_received.greet("Bob") end it "verifies mock expectations set on anonymous fakes" do greeter = fake mock(greeter).greet("Jake") { "Hello Jake" } expect { Bogus.after_each_test }.to raise_error(Bogus::NotAllExpectationsSatisfied) end end class SampleOfConfiguredFake def self.foo(x) end def self.bar(x, y) end def self.baz end end describe "globally configured fakes" do before do Bogus.fakes do fake(:globally_configured_fake, as: :class, class: proc{SampleOfConfiguredFake}) do foo "foo" bar { "bar" } baz { raise "oh noes!" } end end end it "returns configured fakes" do the_fake = Stubber.fake(:globally_configured_fake) expect(the_fake.foo('a')).to eq "foo" expect(the_fake.bar('a', 'b')).to eq "bar" end it "allows overwriting stubbed methods" do the_fake = Stubber.fake(:globally_configured_fake, bar: "baz") expect(the_fake.foo('a')).to eq "foo" expect(the_fake.bar('a', 'b')).to eq "baz" end it "evaluates the block passed to method in configuration when method is called" do the_fake = Stubber.fake(:globally_configured_fake) expect{ the_fake.baz }.to raise_error("oh noes!") end end describe "faking classes" do class ThisClassWillBeReplaced def self.hello(name) "Hello, #{name}" end end TheOriginalClass = ThisClassWillBeReplaced after do Bogus.reset_overwritten_classes end it "replaces the class for the duration of the test" do Stubber.fake_class(ThisClassWillBeReplaced, hello: "replaced!") expect(ThisClassWillBeReplaced.hello("foo")).to eq "replaced!" expect(ThisClassWillBeReplaced).to_not equal(TheOriginalClass) end it "makes it possible to spy on classes" do Stubber.fake_class(ThisClassWillBeReplaced) ThisClassWillBeReplaced.hello("foo") expect(ThisClassWillBeReplaced).to Bogus.have_received.hello("foo") expect(ThisClassWillBeReplaced).to_not Bogus.have_received.hello("bar") end it "restores the class after the test has finished" do Stubber.fake_class(ThisClassWillBeReplaced) Bogus.reset_overwritten_classes expect(ThisClassWillBeReplaced).to equal(TheOriginalClass) end end class SampleForContracts def initialize(name) @name = name end def greet(greeting = "Hello") "#{greeting}, #{@name}!" end end describe "contracts" do let(:sample) { SampleForContracts.new("John") } before do Bogus.reset! Stubber.fake(:sample_for_contracts, greet: "Welcome, John!") Bogus.after_each_test Bogus.record_calls_for(:sample_for_contracts, SampleForContracts) end it "passes when all the mocked interactions were executed" do expect(sample.greet("Welcome")).to eq "Welcome, John!" Bogus.after_each_test expect { Bogus.verify_contract!(:sample_for_contracts) }.not_to raise_error end it "fails when contracts are fullfilled" do expect(sample.greet("Hello")).to eq "Hello, John!" Bogus.after_each_test expect { Bogus.verify_contract!(:sample_for_contracts) }.to raise_error(Bogus::ContractNotFulfilled) end end end bogus-0.1.6/spec/bogus/rspec/0000755000004100000410000000000012454377662016072 5ustar www-datawww-databogus-0.1.6/spec/bogus/rspec/syntax_spec.rb0000644000004100000410000000054112454377662020757 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::RSpecSyntax do context = self let(:syntax) { Bogus::RSpecSyntax.new(context) } it "gets the described class" do expect(syntax.described_class).to eq(Bogus::RSpecSyntax) end it "can set the described class" do syntax.described_class = Object expect(described_class).to eq(Object) end end bogus-0.1.6/spec/bogus/stubbing/0000755000004100000410000000000012454377662016573 5ustar www-datawww-databogus-0.1.6/spec/bogus/stubbing/shadow_spec.rb0000644000004100000410000001313712454377662021424 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::Shadow do let(:object) { Samples::FooFake.new } let(:shadow) { Bogus::Shadow.new } shared_examples_for "spying on shadows" do context "spying" do before do shadow.run(:foo, "a", "b") rescue nil # for when the method raises an error end it "returns the called methods" do expect(shadow.has_received(:foo, ["a", "b"])).to be(true) end it "does not return true for interactions that did not happen" do expect(shadow.has_received(:foo, ["a", "c"])).to be(false) expect(shadow.has_received(:bar, ["a", "c"])).to be(false) end end end context "unrecorded interactions" do it "returns an unstubbed value" do return_value = shadow.run(:foo, "a", "b") expect(return_value).to be_a_default_return_value end include_examples "spying on shadows" end context "interactions that raise exceptions" do class SomeWeirdException < StandardError; end before do shadow.stubs(:foo, "a", "b") { raise SomeWeirdException, "failed!" } end it "raises the error when called" do expect { shadow.run(:foo, "a", "b") }.to raise_error(SomeWeirdException, "failed!") end include_examples "spying on shadows" end context "interactions with no return value" do before do shadow.stubs(:foo, ["a", "b"]) end it "returns the default value" do expect(shadow.run(:foo, ["a", "b"])).to be_a_default_return_value end include_examples "spying on shadows" end context "interactions with AnyArgs" do before do shadow.stubs(:foo, "a", "b") { "old specific value" } shadow.stubs(:foo, Bogus::AnyArgs) { "default value" } shadow.stubs(:foo, "a", "d") { "new specific value" } end it "changes the default value returned from method" do expect(shadow.run(:foo, "b", "c")).to eq("default value") end it "overwrites the old specific stubbed values" do expect(shadow.run(:foo, "a", "b")).to eq("default value") end it "does not affect the new specific stubbed values" do expect(shadow.run(:foo, "a", "d")).to eq("new specific value") end it "allows spying on calls using any args" do shadow.run(:foo, "a", "c") expect(shadow.has_received(:foo, [Bogus::AnyArgs])).to be(true) end end context "interactions that take anything" do before do shadow.stubs(:foo, "a", Bogus::Anything) { "return value" } end it "changes the return value for calls that match" do expect(shadow.run(:foo, "a", "c")).to eq("return value") end it "does not affect the return value for other calls" do shadow.stubs(:foo, "a", "b") { "specific value" } expect(shadow.run(:foo, "a", "b")).to eq("specific value") end it "allows spying on calls using anything in args" do shadow.run(:foo, "a", "b") expect(shadow.has_received(:foo, [Bogus::Anything, "b"])).to be(true) end end context "stubbed interactions" do before do shadow.stubs(:foo, "a", "b") { "stubbed value" } end it "returns the stubbed value" do expect(shadow.run(:foo, "a", "b")).to eq("stubbed value") end it "returns the latest stubbed value" do shadow.stubs(:foo, "a", "b") { "stubbed twice" } shadow.stubs(:foo, "b", "c") { "different params" } expect(shadow.run(:foo, "a", "b")).to eq("stubbed twice") expect(shadow.run(:foo, "b", "c")).to eq("different params") end it "returns the default value for non-stubbed calls" do expect(shadow.run(:foo, "c", "d")).to be_a_default_return_value expect(shadow.run(:bar)).to be_a_default_return_value end it "does not contribute towards unsatisfied interactions" do expect(shadow.unsatisfied_interactions).to be_empty end it "adds required interaction when mocking over stubbing" do shadow.mocks(:foo, "a", "b") { "stubbed value" } expect(shadow.unsatisfied_interactions).not_to be_empty end include_examples "spying on shadows" end context "mocked interactions" do before do shadow.mocks(:foo, "a", "b") { "mocked value" } end it "returns the mocked value" do expect(shadow.run(:foo, "a", "b")).to eq("mocked value") end it "overwrites the stubbed value" do shadow.stubs(:foo, "a", "c") { "stubbed value" } shadow.mocks(:foo, "a", "c") { "mocked value" } expect(shadow.run(:foo, "a", "c")).to eq("mocked value") end it "is overwritten by stubbing" do shadow.mocks(:foo, "a", "c") { "mocked value" } shadow.stubs(:foo, "a", "c") { "stubbed value" } expect(shadow.run(:foo, "a", "c")).to eq("stubbed value") end it "removes the required interaction when stubbing over mocking" do shadow.stubs(:foo, "a", "b") { "stubbed value" } expect(shadow.unsatisfied_interactions).to be_empty end it "returns the default value for non-stubbed calls" do expect(shadow.run(:foo, "a", "c")).to be_a_default_return_value end it "contributes towards unsatisfied interactions" do interactions = shadow.unsatisfied_interactions expect(interactions.size).to eq(1) expect(interactions.first.method).to eq(:foo) expect(interactions.first.args).to eq(["a", "b"]) end it "removes the staisfied expectations from unsatisfied interactions" do shadow.mocks(:with_optional_args, 'a') shadow.run(:with_optional_args, 'a', Bogus::DefaultValue) shadow.run(:foo, "a", "b") expect(shadow.unsatisfied_interactions).to be_empty end include_examples "spying on shadows" end end bogus-0.1.6/spec/bogus/stubbing/tracks_existence_of_test_doubles_spec.rb0000644000004100000410000000107312454377662026731 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::TracksExistenceOfTestDoubles do let(:tracker) { Bogus::TracksExistenceOfTestDoubles.new } it "returns an empty double list with nothing tracked" do expect(tracker.doubles).to eq([]) end it "lists the added test doubles in order without duplicates" do foo = "foo" bar = 1 baz = Object.new tracker.track foo tracker.track bar tracker.track foo tracker.track baz tracker.track baz tracker.track bar tracker.track foo expect(tracker.doubles).to eq([foo, bar, baz]) end end bogus-0.1.6/spec/bogus/stubbing/stubbing_existing_methods_on_fakes_spec.rb0000644000004100000410000000214612454377662027254 0ustar www-datawww-data require 'spec_helper' describe "Stubbing existing methods on fakes" do before do extend Bogus::MockingDSL Bogus.clear end it "should be possible to stub to_s" do foo = fake(:foo) { Samples::Foo } stub(foo).to_s { "I'm a foo" } expect(foo.to_s).to eq("I'm a foo") end it "should be possible to mock to_s" do foo = fake(:foo) { Samples::Foo } mock(foo).to_s { "I'm a foo" } expect { Bogus.after_each_test }.to raise_exception(Bogus::NotAllExpectationsSatisfied) end it "should be possible to stub to_s on anonymous fake" do foo = fake(to_s: "I'm a foo") expect(foo.to_s).to eq("I'm a foo") end class Object def sample_method_for_stubbing_existing_methods end end class SampleForStubbingExistingMethods end it "should be possible to stub arbitrary methods that were defined on Object" do foo = fake(:foo) { SampleForStubbingExistingMethods } stub(foo).sample_method_for_stubbing_existing_methods { :bar } expect(foo.sample_method_for_stubbing_existing_methods).to eq(:bar) end end bogus-0.1.6/spec/bogus/stubbing/verifies_stub_definition_spec.rb0000644000004100000410000000462212454377662025217 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::VerifiesStubDefinition do class ExampleForVerify def foo(bar) end def three_args(x, y, z) end def optional_args(x, y = 1, z = 2) end def var_args(x, *y) end end let(:object) { ExampleForVerify.new } let(:verifies_stub_definition) { Bogus::VerifiesStubDefinition.new(method_stringifier) } let(:method_stringifier) { isolate(Bogus::MethodStringifier) } def verify(method_name, args) verifies_stub_definition.verify!(object, method_name, args) end def it_allows(method_name, args) expect{ verify(method_name, args) }.not_to raise_error end def it_disallows(method_name, args, error = ArgumentError) expect{ verify(method_name, args) }.to raise_error(error) end def self.it_allows_argument_numbers(method_name, *arg_counts) arg_counts.each do |arg_count| it "allows #{arg_count} arguments" do it_allows(method_name, [1] * arg_count) end end end def self.it_disallows_argument_numbers(method_name, *arg_counts) arg_counts.each do |arg_count| it "disallows #{arg_count} arguments" do it_disallows(method_name, [1] * arg_count) end end end it "checks for method presence" do it_disallows(:bar, [1], NameError) end it "allows interactions that use any_args" do it_allows(:three_args, [Bogus::AnyArgs]) end describe "method arity checks" do context "method with positive arity" do it_allows_argument_numbers :three_args, 3 it_disallows_argument_numbers :three_args, 2, 4 end context "method with optional arguments" do it_allows_argument_numbers :optional_args, 1, 2, 3 it_disallows_argument_numbers :optional_args, 0, 4 end context "method with infinite number of arguments" do it_allows_argument_numbers :var_args, 1000 it_disallows_argument_numbers :var_args, 0 end end class UsesMethodMissing def respond_to?(method) method == :foo end def method_missing(name, *args, &block) return super unless name == :foo :bar end end context "with objects that use method missing" do let(:object) { UsesMethodMissing.new } it "allows stubbing methods that the object responds to" do it_allows(:foo, []) end it "disallows stubbing methods that the object does not respond to" do it_disallows(:bar, [], NameError) end end end bogus-0.1.6/spec/bogus/stubbing/resets_stubbed_methods_spec.rb0000644000004100000410000000072412454377662024675 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::ResetsStubbedMethods do let(:double_tracker) { double } let(:overwrites_methods) { double } let(:resets_stubbed_methods) { isolate(Bogus::ResetsStubbedMethods) } it "resets all stubbed objects back to previous implementation" do foo = double allow(double_tracker).to receive(:doubles) { [foo] } expect(overwrites_methods).to receive(:reset).with(foo) resets_stubbed_methods.reset_all_doubles end end bogus-0.1.6/spec/bogus/stubbing/ensures_all_interactions_satisfied_spec.rb0000644000004100000410000000244612454377662027271 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::EnsuresAllInteractionsSatisfied do let(:ensures_all_interactions_satisfied) { isolate(Bogus::EnsuresAllInteractionsSatisfied) } it "does nothing with all interactions satisfied" do objects = 3.times.map { |n| Samples::FooFake.new } expect { ensures_all_interactions_satisfied.ensure_satisfied!(objects) }.not_to raise_error end it "raises an error enumerating satisfied and unsatisfied interactions" do foo = Samples::FooFake.new foo.__shadow__.mocks(:foo, "a", "b") { "result" } foo.__shadow__.mocks(:foo, "a", "c") { "result 2" } foo.__shadow__.run(:foo, "a", "b") bar = Samples::FooFake.new bar.__shadow__.stubs(:foo, "a", "b") { "result" } bar.__shadow__.stubs(:foo, "a", "c") { "result 2" } bar.__shadow__.run(:foo, "a", "b") bar.__shadow__.run(:foo, "x", "y") msg = <<-EOF Some of the mocked interactions were not satisfied: - #{foo.inspect}.foo("a", "c") The following calls were recorded: - #{foo.inspect}.foo("a", "b") - #{bar.inspect}.foo("a", "b") - #{bar.inspect}.foo("x", "y") EOF expect { ensures_all_interactions_satisfied.ensure_satisfied!([foo, bar]) }.to raise_error(Bogus::NotAllExpectationsSatisfied, msg.gsub(/ {4}/, '')) end end bogus-0.1.6/spec/bogus/stubbing/double_spec.rb0000644000004100000410000000474712454377662021420 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe Double do shared_examples_for "double behavior" do it "tracks existence of test doubles" do expect(double_tracker).to receive(:track).with(object) double_instance.stub.foo("a", "b") { "the result" } end it "does not track existence of the double if verify fails" do allow(verifies_stub_definition).to receive(:verify!).with(object, :foo, ["a", "b"]) { raise NameError } expect { double_instance.stub.foo("a", "b") { "the result" } }.to raise_error expect(double_tracker).not_to have_received(:track).with(object) end it "verifies stub definition" do expect(verifies_stub_definition).to receive(:verify!).with(object, :foo, ["a", "b"]) double_instance.stub.foo("a", "b") { "the result" } end it "stubs shadow methods" do object.extend RecordInteractions expect(object.__shadow__).to receive(:stubs).with(:foo, "a", "b") double_instance.stub.foo("a", "b") { "the result" } end it "mocks shadow methods" do object.extend RecordInteractions expect(object.__shadow__).to receive(:mocks).with(:foo, "a", "b") double_instance.mock.foo("a", "b") { "the result" } end it "adds method overwriting" do double_instance.stub.foo("a", "b") { "the result" } expect(overwrites_methods.overwrites).to eq([[object, :foo]]) end it "records double interactions" do expect(records_double_interactions).to receive(:record).with(object, :foo, ["a", "b"]) double_instance.stub.foo("a", "b") { "the result" } end end let(:double_tracker) { double(:double_tracker, track: nil) } let(:verifies_stub_definition) { double(:verifies_stub_definition, verify!: nil) } let(:records_double_interactions) { double(:records_double_interactions, record: nil) } let(:overwrites_methods) { FakeMethodOverwriter.new } let(:double_instance) { isolate(Double) } context "with regular objects" do let(:object) { Samples::Foo.new } include_examples "double behavior" end context "with fakes" do let(:object) { Samples::FooFake.new } include_examples "double behavior" end class FakeMethodOverwriter def overwrite(object, method) overwrites << [object, method] object.extend RecordInteractions end def overwrites @overwrites ||= [] end end end end bogus-0.1.6/spec/bogus/stubbing/anything_spec.rb0000644000004100000410000000045412454377662021756 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::Anything do it "is equal to everything" do anything = Bogus::Anything expect(anything).to eq("foo") expect(anything).to eq("bar") expect(anything).to eq(1) expect(anything).to eq(Object.new) expect(anything).to eq(anything) end end bogus-0.1.6/spec/bogus/stubbing/interaction_spec.rb0000644000004100000410000001065712454377662022462 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe Interaction do class SomeError < StandardError; end same = [ [[:foo, [:bar], "value"], [:foo, [:bar], "value"]], [[:foo, [:bar, DefaultValue], "value"], [:foo, [:bar], "value"]], [[:foo, [:bar, {foo: DefaultValue}], "value"], [:foo, [:bar], "value"]], [[:foo, [:bar, {foo: DefaultValue, bar: 1}], "value"], [:foo, [:bar, {bar: 1}], "value"]], [[:foo, [DefaultValue, {foo: DefaultValue}], "value"], [:foo, [], "value"]], [[:foo, [:bar]], [:foo, [:bar], "value"]], [[:foo, [:bar], "value"], [:foo, [:bar]]], [[:foo, [:bar]], [:foo, [:bar]]], [[:foo, [:bar]], [:foo, [AnyArgs]]], [[:foo, [:bar], "same value"], [:foo, [AnyArgs], "same value"]], [[:foo, [:bar, :baz]], [:foo, [:bar, Anything]]], [[:foo, [1], "same value"], [:foo, [WithArguments.new{|n| n.odd?}], "same value"]], [[:foo, [1]], [:foo, [SameClass.new(Integer)]]] ] different = [ [[:foo, [:bar], "value"], [:foo, [:bar], "value2"]], [[:foo, [:bar, :baz], "value"], [:foo, [:baz, Anything], "value"]], [[:foo, [nil, {foo: DefaultValue}], "value"], [:foo, [], "value"]], [[:foo, [DefaultValue, {foo: DefaultValue}], "value"], [:foo, [{}], "value"]], [[:foo, [:bar], "value"], [:baz, [:bar], "value"]], [[:foo, [{}], "value"], [:foo, [], "value"]], [[:foo, [:baz], "value"], [:foo, [:bar], "value"]], [[:foo, [DefaultValue, :baz], "value"], [:foo, [:bar, :bar], "value"]], [[:foo, [:bar, {foo: DefaultValue, bar: 1}], "value"], [:foo, [:bar, {bar: 2}], "value"]], [[:foo, [:bar]], [:bar, [AnyArgs]]], [[:foo, [:bar], "some value"], [:foo, [AnyArgs], "other value"]], [[:foo, [:bar]], [:foo, [:baz]]], [[:baz, [:bar]], [:foo, [:bar]]], [[:foo, [2], "same value"], [:foo, [WithArguments.new{|n| n.odd?}], "same value"]], [[:foo, [1]], [:foo, [SameClass.new(Symbol)]]] ] def create_interaction(interaction) method_name, args, return_value = interaction if return_value Interaction.new(method_name, args) { return_value } else Interaction.new(method_name, args) end end same.each do |first_interaction, second_interaction| it "returns true for #{first_interaction.inspect} and #{second_interaction.inspect}" do first = create_interaction(first_interaction) second = create_interaction(second_interaction) expect(Interaction.same?(recorded: first, stubbed: second)).to be(true) end end different.each do |first_interaction, second_interaction| it "returns false for #{first_interaction.inspect} and #{second_interaction.inspect}" do first = create_interaction(first_interaction) second = create_interaction(second_interaction) expect(Interaction.same?(recorded: first, stubbed: second)).to be(false) end end it "differs exceptions from empty return values" do first = Interaction.new(:foo, [:bar]) { raise SomeError } second = Interaction.new(:foo, [:bar]) { nil } expect(Interaction.same?(recorded: first, stubbed: second)).to be(false) end it "differs raised exceptions from ones just returned from the block" do first = Interaction.new(:foo, [:bar]) { raise SomeError } second = Interaction.new(:foo, [:bar]) { SomeError } expect(Interaction.same?(recorded: first, stubbed: second)).to be(false) end it "considers exceptions of the same type as equal" do first = Interaction.new(:foo, [:bar]) { raise SomeError } second = Interaction.new(:foo, [:bar]) { raise SomeError } expect(Interaction.same?(recorded: first, stubbed: second)).to be(true) end context 'when comparing arguments with custom #== implementations' do Dev = Struct.new(:login) do def ==(other) login == other.login end end it "considers two interactions == when the arguments are ==" do first = Interaction.new(:with, [Dev.new(:psyho)]) second = Interaction.new(:with, [Dev.new(:psyho)]) expect(Interaction.same?(recorded: first, stubbed: second)).to be(true) end it "considers two interactions != when the arguments are !=" do first = Interaction.new(:with, [Dev.new(:wrozka)]) second = Interaction.new(:with, [Dev.new(:yundt)]) expect(Interaction.same?(recorded: first, stubbed: second)).to be(false) end end end end bogus-0.1.6/spec/bogus/stubbing/have_received_matcher_spec.rb0000644000004100000410000000521212454377662024426 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::HaveReceivedMatcher do let(:verifies_stub_definition) { double(:verifies_stub_definition, verify!: nil) } let(:records_double_interactions) { double(:records_double_interactions, record: nil) } let(:have_received_matcher) { isolate(Bogus::HaveReceivedMatcher) } let(:fake) { Samples::FooFake.new } before do fake.foo("a", "b") end shared_examples_for "have_received_matcher" do it "matches when the spy has received the message" do expect(fake).to bogus_have_received(:foo, "a", "b") end it "does not match if the spy hasn't received the message" do expect(fake).not_to bogus_have_received(:foo, "a", "c") end it "verifies that the method call has the right signature" do expect(verifies_stub_definition).to receive(:verify!).with(fake, :foo, ["a", "b"]) bogus_have_received(:foo, "a", "b") have_received_matcher.matches?(fake) end it "records the interaction so that it can be checked by contract tests" do expect(records_double_interactions).to receive(:record).with(fake, :foo, ["a", "b"]) bogus_have_received(:foo, "a", "b") have_received_matcher.matches?(fake) end it "returns a readable error message for object with no shadow" do bogus_have_received(:upcase) expect(have_received_matcher.matches?("foo")).to be(false) expect(have_received_matcher.failure_message_for_should).to eq(Bogus::HaveReceivedMatcher::NO_SHADOW) expect(have_received_matcher.failure_message).to eq(Bogus::HaveReceivedMatcher::NO_SHADOW) expect(have_received_matcher.failure_message_for_should_not).to eq(Bogus::HaveReceivedMatcher::NO_SHADOW) expect(have_received_matcher.failure_message_when_negated).to eq(Bogus::HaveReceivedMatcher::NO_SHADOW) end it "returns a readable error message for fakes" do bogus_have_received(:foo, "a", "c") have_received_matcher.matches?(fake) message = %Q{Expected #{fake.inspect} to have received foo("a", "c"), but it didn't.\n\n}+ %Q{The recorded interactions were:\n} + %Q{ - foo("a", "b")\n} expect(have_received_matcher.failure_message_for_should).to eq(message) expect(have_received_matcher.failure_message).to eq(message) end end context "with method_missing builder" do def bogus_have_received(method, *args) have_received_matcher.build.__send__(method, *args) end include_examples "have_received_matcher" end context "with method call builder" do def bogus_have_received(*args) have_received_matcher.build(*args) end include_examples "have_received_matcher" end end bogus-0.1.6/spec/bogus/stubbing/overwrites_methods_spec.rb0000644000004100000410000000530612454377662024072 0ustar www-datawww-datarequire 'spec_helper' module Bogus describe OverwritesMethods do let(:method_stringifier) { MethodStringifier.new } let(:makes_substitute_methods) { isolate(MakesSubstituteMethods) } let(:overwriter) { isolate(OverwritesMethods) } let(:object) { SampleOfOverwriting.new } context "with regular objects" do class SampleOfOverwriting def greet(name) "Hello #{name}" end def wave(part_of_body = "hand", speed = "slowly") "I'm waving my #{part_of_body} #{speed}" end end before do overwriter.overwrite(object, :greet) end it "does not change the method signature" do expect(object.method(:greet).arity).to eq(1) end it "does not change the method signature" do expect { object.greet("John", "Paul") }.to raise_error(ArgumentError) end it "adds interaction recording to the overwritten object" do object.greet("John") expect(object).to Bogus.have_received.greet("John") expect(object).not_to Bogus.have_received.greet("Paul") end it "can reset the overwritten methods" do overwriter.reset(object) expect(object.greet("John")).to eq("Hello John") end it "is imdepotent when overwriting" do overwriter.overwrite(object, :greet) overwriter.overwrite(object, :greet) overwriter.overwrite(object, :greet) overwriter.reset(object) expect(object.greet("John")).to eq("Hello John") end end context "with objects that use method missing" do class UsesMethodMissing def respond_to?(name) name == :greet end def method_missing(name, *args, &block) "the original return value" end end let(:object) { UsesMethodMissing.new } before do overwriter.overwrite(object, :greet) end it "can overwrite the non-existent methods" do expect(object.methods).to include(:greet) end it "can be reset back to the original state" do overwriter.overwrite(object, :greet) overwriter.overwrite(object, :greet) overwriter.reset(object) expect(object.greet).to eq("the original return value") end end context "with fakes" do let(:fake) { Samples::FooFake.new } it "does nothing because fakes methods already work as we need" do overwriter.overwrite(fake, :foo_bar) expect(fake).not_to respond_to(:foo_bar) end it "does not reset fakes, because there is nothing to reset" do expect { overwriter.reset(fake) }.not_to raise_error end end end end bogus-0.1.6/spec/bogus/stubbing/record_interactions_spec.rb0000644000004100000410000000120712454377662024172 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::RecordInteractions do class SampleRecordsInteractions include Bogus::RecordInteractions end let(:sample) { SampleRecordsInteractions.new } it "allows verifying that interactions happened" do sample.__record__(:foo, 1, 2, 3) expect(sample.__shadow__.has_received(:foo, [1,2,3])).to be(true) end it "allows verifying that interactions didn't happen" do sample.__record__(:bar) expect(sample.__shadow__.has_received(:foo, [1,2,3])).to be(false) end it "returns self from record by default" do expect(sample.__record__(:foo)).to be_a_default_return_value end end bogus-0.1.6/spec/bogus/stubbing/undefined_return_value_spec.rb0000644000004100000410000000102512454377662024664 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::UndefinedReturnValue do let(:interaction) { Bogus::Interaction.new(:foo, ["bar"]) } let(:undefined_return_value) { Bogus::UndefinedReturnValue.new(interaction) } it "includes the interaction when stringified" do expect(undefined_return_value.to_s).to include('foo("bar")') end it "includes interaction in the error message unknown method called" do begin undefined_return_value.foobar rescue => e expect(e.message).to include('foo("bar")') end end end bogus-0.1.6/spec/bogus/stubbing/multi_stubber_spec.rb0000644000004100000410000000150712454377662023015 0ustar www-datawww-datarequire 'spec_helper' describe Bogus::MultiStubber do let(:fake_double) { FakeDouble.new } let(:bogus_any_args) { Bogus::AnyArgs } let(:create_double) { proc{ fake_double } } let(:multi_stubber) { isolate(Bogus::MultiStubber) } it "stubs all the given methods with any args returning the given value" do multi_stubber.stub_all(Object.new, foo: 1, bar: 2) expect(fake_double.stubbed).to eq([[:foo, [bogus_any_args], 1], [:bar, [bogus_any_args], 2]]) end it "uses passed procs as the return value block" do multi_stubber.stub_all(Object.new, foo: proc{ 1 }) expect(fake_double.stubbed).to eq([[:foo, [bogus_any_args], 1]]) end class FakeDouble def stubbed @stubbed ||= [] end def stubs(name, *args, &return_value) stubbed << [name, args, return_value.call] end end end bogus-0.1.6/spec/support/0000755000004100000410000000000012454377662015353 5ustar www-datawww-databogus-0.1.6/spec/support/matchers.rb0000644000004100000410000000012312454377662017502 0ustar www-datawww-datadef be_a_default_return_value be_an_instance_of(Bogus::UndefinedReturnValue) end bogus-0.1.6/spec/support/fake_creator_of_fakes.rb0000644000004100000410000000042612454377662022164 0ustar www-datawww-dataclass FakeCreatorOfFakes def create(name, opts = {}, &block) fake = [name, opts, block && block.call] fakes << fake fake end def fakes @fakes ||= [] end def has_created?(name, opts = {}, klass = nil) fakes.include?([name, opts, klass]) end end bogus-0.1.6/spec/support/sample_fake.rb0000644000004100000410000000036412454377662020152 0ustar www-datawww-datamodule Samples class Foo def foo(a, b) "the real foo: #{a} #{b}" end def bar "the real bar" end def with_optional_args(a, b = :opt) end end FooFake = Bogus::Injector.new.copies_classes.copy(Foo) end bogus-0.1.6/spec/support/shared_examples_for_keyword_arguments.rb0000644000004100000410000000316712454377662025552 0ustar www-datawww-datashared_examples_for "stubbing methods with keyword arguments" do it "can spy on stubbed methods" do stub(subject).foo(any_args) subject.foo(x: "test") expect(subject).to have_received.foo(x: "test") expect(subject).not_to have_received.foo(x: "baz") end it "can mock methods with keyword arguments" do mock(subject).foo(x: 1) { :return } expect(subject.foo(x: 1)).to eq(:return) expect { Bogus.after_each_test }.not_to raise_error end it "can stub methods with keyword arguments" do stub(subject).foo(x: "bar") { :return_value } expect(subject.foo(x: "bar")).to eq(:return_value) end it "raises on error on unknown keyword" do expect { stub(subject).foo(x: "bar", baz: "baz") }.to raise_error(ArgumentError) end it "does not overwrite the method signature" do stub(subject).foo(x: 1) expect { subject.foo(bar: 1) }.to raise_error(ArgumentError) end end shared_examples_for "stubbing methods with double splat" do it "can spy on stubbed methods" do stub(subject).bar(any_args) subject.bar(x: "test", z: "spec") expect(subject).to have_received.bar(x: "test", z: "spec") expect(subject).not_to have_received.bar(x: "test", y: "baz") end it "can mock methods with keyword arguments" do mock(subject).bar(x: 1, z: 2) { :return } expect(subject.bar(x: 1, z: 2)).to eq(:return) expect { Bogus.after_each_test }.not_to raise_error end it "can stub methods with keyword arguments" do stub(subject).bar(x: "bar", z: "bar") { :return_value } expect(subject.bar(x: "bar", z: "bar")).to eq(:return_value) end end bogus-0.1.6/spec/support/ruby_features.rb0000644000004100000410000000042712454377662020562 0ustar www-datawww-datamodule RubyFeatures module_function def keyword_arguments? ruby?('2.0') && !rbx? end def required_keyword_arguments? ruby?('2.1') && keyword_arguments? end def ruby?(version) RUBY_VERSION >= version end def rbx? RUBY_ENGINE == 'rbx' end end bogus-0.1.6/.travis.yml0000644000004100000410000000021412454377662015013 0ustar www-datawww-datalanguage: ruby rvm: - 1.9.3 - 2.0 - 2.1.1 - jruby-19mode - rbx script: bundle exec rspec spec && bundle exec cucumber --tag ~@wip bogus-0.1.6/lib/0000755000004100000410000000000012454377662013453 5ustar www-datawww-databogus-0.1.6/lib/bogus/0000755000004100000410000000000012454377662014572 5ustar www-datawww-databogus-0.1.6/lib/bogus/core_ext.rb0000644000004100000410000000141212454377662016725 0ustar www-datawww-data# This monkey patch should not break Ruby compatibility # but is necessary because MRI, instead of calling object.kind_of?(module), # calls the C function, which implements kind_of. This makes # using fake objects in switch cases produce unexpected results: # # fake = fake(:library) { Library } # # case fake # when Library then "bingo!" # else raise "oh noes!" # end # # Without the patch, the snippet above raises 'oh noes!' # instead of returning 'bingo!'. class Module # don't warn about redefining === method Bogus::Support.supress_warnings do alias :__trequals__ :=== def ===(object) # BasicObjects do not have kind_of? method return __trequals__(object) unless Object.__trequals__(object) object.kind_of?(self) end end end bogus-0.1.6/lib/bogus/configuration.rb0000644000004100000410000000026612454377662017772 0ustar www-datawww-datamodule Bogus class Configuration attr_writer :search_modules attr_accessor :fake_ar_attributes def search_modules @search_modules ||= [Object] end end end bogus-0.1.6/lib/bogus/proxies_method_calls.rb0000644000004100000410000000073712454377662021335 0ustar www-datawww-datamodule Bogus module ProxiesMethodCalls def proxy(method_name) MethodCallProxy.new do |name, *args, &return_value| __send__(method_name, name, *args, &return_value) end end end class MethodCallProxy < BasicObject def initialize(&on_called) @on_called = on_called end def raise(*args) ::Kernel.raise(*args) end def method_missing(name, *args, &block) @on_called.call(name, *args, &block) end end end bogus-0.1.6/lib/bogus/contracts/0000755000004100000410000000000012454377662016572 5ustar www-datawww-databogus-0.1.6/lib/bogus/contracts/recording_proxy.rb0000644000004100000410000000116212454377662022334 0ustar www-datawww-dataclass Bogus::RecordingProxy < BasicObject extend ::Bogus::Takes takes :instance, :fake_name, :interactions_repository def method_missing(name, *args, &block) returned_value = @instance.__send__(name, *args, &block) @interactions_repository.record(@fake_name, name, *args) { returned_value } returned_value rescue => e @interactions_repository.record(@fake_name, name, *args) { ::Kernel.raise(e) } ::Kernel.raise end # apparently even BasicObject has an equality operator def ==(other) method_missing(:==, other) end def respond_to?(name) @instance.respond_to?(name) end end bogus-0.1.6/lib/bogus/contracts/verifies_contracts.rb0000644000004100000410000000074612454377662023022 0ustar www-datawww-datamodule Bogus class VerifiesContracts extend Takes takes :doubled_interactions, :real_interactions def verify(fake_name) missed = doubled_interactions.for_fake(fake_name).reject do |interaction| real_interactions.recorded?(fake_name, interaction) end unless missed.empty? actual = real_interactions.for_fake(fake_name) raise Bogus::ContractNotFulfilled.new(fake_name, missed: missed, actual: actual) end end end end bogus-0.1.6/lib/bogus/contracts/records_double_interactions.rb0000644000004100000410000000047112454377662024676 0ustar www-datawww-datamodule Bogus class RecordsDoubleInteractions extend Takes takes :doubled_interactions, :fake_registry def record(object, method_name, args, &block) fake_name = fake_registry.name(object) doubled_interactions.record(fake_name, method_name, *args, &block) if fake_name end end end bogus-0.1.6/lib/bogus/contracts/adds_recording.rb0000644000004100000410000000054212454377662022067 0ustar www-datawww-datamodule Bogus class AddsRecording extend Takes takes :create_proxy_class, :overwrites_classes, :overwritten_classes def add(name, klass) new_klass = create_proxy_class.call(name, klass) overwrites_classes.overwrite(klass.name, new_klass) overwritten_classes.add(klass.name, klass) new_klass end end end bogus-0.1.6/lib/bogus/contracts/contract_not_fulfilled.rb0000644000004100000410000000136512454377662023647 0ustar www-datawww-datamodule Bogus class ContractNotFulfilled < StandardError attr_reader :fake_name, :missed_interactions, :actual_interactions def initialize(fake_name, opts = {}) @fake_name = fake_name @actual_interactions = opts.fetch(:actual) @missed_interactions = opts.fetch(:missed) super(message) end def message str = <<-EOF Contract not fullfilled for #{fake_name}! Missed interactions: #{interactions_str(missed_interactions)} Actual interactions: #{interactions_str(actual_interactions)} EOF str.gsub(' ' * 6, '') end private def interactions_str(interactions) interactions.map { |i| " - #{InteractionPresenter.new(i)}" }.join("\n") end end end bogus-0.1.6/lib/bogus/contracts/interactions_repository.rb0000644000004100000410000000076412454377662024127 0ustar www-datawww-datamodule Bogus class InteractionsRepository def initialize @interactions = Hash.new { |hash, fake_name| hash[fake_name] = [] } end def record(fake_name, method, *args, &block) @interactions[fake_name] << Interaction.new(method, args, &block) end def recorded?(fake_name, interaction) @interactions[fake_name].any?{ |i| Interaction.same?(stubbed: interaction, recorded: i) } end def for_fake(fake_name) @interactions[fake_name] end end end bogus-0.1.6/lib/bogus/contracts/adds_contract_verification.rb0000644000004100000410000000236312454377662024475 0ustar www-datawww-datamodule Bogus class AddsContractVerification extend Takes takes :adds_recording, :verifies_contracts, :converts_name_to_class, :syntax def add(fake_name, &block) old_described_class = syntax.described_class before do new_class = adds_recording.add(fake_name, class_to_overwrite(fake_name, block)) syntax.described_class = new_class if overwritten_described_class?(block) end after do syntax.described_class = old_described_class if overwritten_described_class?(block) end after_suite { verifies_contracts.verify(fake_name) } end private def overwritten_described_class?(block) described_class && !custom_class(block) end def class_to_overwrite(fake_name, block) custom_class(block) || described_class || fake_class(fake_name) end def custom_class(block) block.call if block end def described_class syntax.described_class end def fake_class(name) converts_name_to_class.convert(name) end def after_suite(&block) syntax.after_suite { block.call } end def after(&block) syntax.after { block.call } end def before(&block) syntax.before { block.call } end end end bogus-0.1.6/lib/bogus/contracts/proxy_class.rb0000644000004100000410000000141012454377662021461 0ustar www-datawww-datamodule Bogus class ProxyClass < Module def initialize(fake_name, klass, create_recording_proxy) @fake_name = fake_name @klass = klass @create_recording_proxy = create_recording_proxy @recording_proxy = @create_recording_proxy.call(@klass, @fake_name) end def self.create(fake_name, klass, create_recording_proxy) end def new(*args, &block) instance = @klass.new(*args, &block) @create_recording_proxy.call(instance, @fake_name) end def method_missing(name, *args, &block) @recording_proxy.__send__(name, *args, &block) end def const_missing(name) @recording_proxy.__send__(:const_get, name) end def respond_to?(name) @recording_proxy.respond_to?(name) end end end bogus-0.1.6/lib/bogus/minitest.rb0000644000004100000410000000205712454377662016757 0ustar www-datawww-datagem 'minitest', '>= 4.7' require 'bogus' module MiniTest::Assertions def assert_received(subject, method, args, message = nil) with_bogus_matcher_for(subject, method, args) do |matcher, result| assert(result, message || matcher.failure_message_for_should) end end def refute_received(subject, method, args, message = nil) with_bogus_matcher_for(subject, method, args) do |matcher, result| refute(result, message || matcher.failure_message_for_should_not) end end private def with_bogus_matcher_for(subject, method, args) matcher = Bogus.have_received.__send__(method, *args) result = matcher.matches?(subject) yield matcher, result end end module Bogus::Minitest include Bogus::MockingDSL def before_setup super Bogus.clear end def after_teardown Bogus.ensure_all_expectations_satisfied! super end end # minitest 5 vs 4.7 if defined? Minitest::Test class Minitest::Test include Bogus::Minitest end else class MiniTest::Unit::TestCase include Bogus::Minitest end end bogus-0.1.6/lib/bogus/support.rb0000644000004100000410000000026412454377662016635 0ustar www-datawww-datamodule Bogus module Support def self.supress_warnings old_verbose = $VERBOSE $VERBOSE = nil yield ensure $VERBOSE = old_verbose end end end bogus-0.1.6/lib/bogus/mocking_dsl.rb0000644000004100000410000000135512454377662017414 0ustar www-datawww-datamodule Bogus module MockingDSL def fake(*args, &block) Bogus.fake_for(*args, &block) end def fake_class(name, opts = {}) Bogus.fake_class(name, opts) end def stub(*args) Bogus.create_stub(*args) end def have_received(*args) Bogus.have_received(*args) end def mock(*args) Bogus.create_mock(*args) end def make_duck(*args) Bogus.make_duck(*args) end def any_args Bogus::AnyArgs end def with(&block) Bogus::WithArguments.new(&block) end def matches(&block) Bogus::MatchesArgument.new(&block) end def any(klass) Bogus::SameClass.new(klass) end def anything Bogus::Anything end end end bogus-0.1.6/lib/bogus/fake_configuration.rb0000644000004100000410000000274112454377662020760 0ustar www-datawww-datamodule Bogus class FakeConfiguration def include?(name) fakes.key?(name) end def fake(name, opts = {}, &block) opts = opts.dup class_block = opts.delete(:class) fakes[name] = FakeDefinition.new(name: name, opts: opts, stubs: stubs_hash(&block), class_block: class_block) end def evaluate(&block) instance_eval(&block) end def get(name) fakes[name] end private def stubs_hash(&block) stubs = StubsConfiguration.new(&block) stubs.stubs end def fakes @fakes ||= {} end end class FakeDefinition attr_reader :name, :class_block, :opts, :stubs def initialize(attrs = {}) @name = attrs[:name] @class_block = attrs[:class_block] @opts = attrs[:opts] || {} @stubs = attrs[:stubs] || {} end def merge(other) FakeDefinition.new(name: other.name, opts: opts.merge(other.opts), stubs: stubs.merge(other.stubs), class_block: other.class_block || class_block) end end class StubsConfiguration include ProxiesMethodCalls def initialize(&block) proxy(:add_stub).instance_eval(&block) if block end def add_stub(name, value = nil, &block) stubs[name] = block || value end def stubs @stubs ||= {} end end end bogus-0.1.6/lib/bogus/version.rb0000644000004100000410000000004512454377662016603 0ustar www-datawww-datamodule Bogus VERSION = "0.1.6" end bogus-0.1.6/lib/bogus/public_methods.rb0000644000004100000410000000341712454377662020125 0ustar www-datawww-datamodule Bogus module PublicMethods def record_calls_for(name, klass = nil) inject.adds_recording.add(name, klass) end def add_contract_verification(syntax, name, &block) inject.adds_contract_verification(syntax).add(name, &block) end def verify_contract!(fake_name) inject.verifies_contracts.verify(fake_name) end def configure(&block) config.tap(&block) end def config inject.configuration end def reset! clear @injector = Bogus::Injector.new end def create_stub(*args) inject.create_stub(*args) end def create_mock(*args) inject.create_mock(*args) end def make_duck(*args) inject.makes_ducks.make(*args) end def have_received(*args) inject.have_received_matcher.build(*args) end def fake_for(*args, &block) inject.creates_fakes_with_stubbed_methods.create(*args, &block) end def fake_class(*args) inject.fakes_classes.fake(*args) end def after_each_test ensure_all_expectations_satisfied! ensure clear end def clear reset_stubbed_methods clear_expectations reset_overwritten_classes end def ensure_all_expectations_satisfied! doubles = inject.double_tracker.doubles inject.ensures_all_interactions_satisfied.ensure_satisfied!(doubles) end def clear_expectations inject.clear_tracked_doubles end def reset_stubbed_methods inject.resets_stubbed_methods.reset_all_doubles end def reset_overwritten_classes inject.resets_overwritten_classes.reset end def fakes(&block) inject.fake_configuration.evaluate(&block) end def inject @injector ||= Bogus::Injector.new end end end bogus-0.1.6/lib/bogus/injector.rb0000644000004100000410000000436312454377662016742 0ustar www-datawww-datamodule Bogus class Injector include Dependor::AutoInject look_in_modules Bogus def configuration @configuration ||= inject(Configuration) end def fake_configuration @fake_configuration ||= inject(FakeConfiguration) end def search_modules configuration.search_modules end def fake_registry @fake_registry ||= inject(FakeRegistry) end def creates_fakes creates_fakes = inject(CreatesFakes) inject(RegistersCreatedFakes, creates_fakes: creates_fakes) end def create_double(object) inject(Double, object: object) end def create_stub(object) create_double(object).stub end def create_mock(object) create_double(object).mock end def instance_methods(klass) inject(InstanceMethods, klass: klass) end def class_methods(klass) inject(ClassMethods, klass: klass) end def active_record_accessors(klass) inject(ActiveRecordAccessors, klass: klass) end def method_copiers copiers = [method(:class_methods), method(:instance_methods)] copiers << method(:active_record_accessors) if configuration.fake_ar_attributes copiers end def have_received_matcher inject(HaveReceivedMatcher) end def interactions_repository raise "Specify either real_interactions or stubbed_interactions" end def double_tracker @double_tracker ||= inject(TracksExistenceOfTestDoubles) end def clear_tracked_doubles @double_tracker = nil end def real_interactions @real_interactions ||= inject(InteractionsRepository) end def doubled_interactions @doubled_interactions ||= inject(InteractionsRepository) end def overwritten_classes @overwritten_classes ||= inject(OverwrittenClasses) end def adds_contract_verification(syntax) inject(AddsContractVerification, syntax: syntax) end def create_proxy_class(fake_name, klass) inject(ProxyClass, fake_name: fake_name, klass: klass) end def create_recording_proxy(instance, fake_name) inject(RecordingProxy, instance: instance, fake_name: fake_name, interactions_repository: real_interactions) end end end bogus-0.1.6/lib/bogus/fakes/0000755000004100000410000000000012454377662015663 5ustar www-datawww-databogus-0.1.6/lib/bogus/fakes/makes_substitute_methods.rb0000644000004100000410000000053712454377662023333 0ustar www-datawww-datamodule Bogus class MakesSubstituteMethods extend Takes takes :method_stringifier def stringify(method) args = method_stringifier.argument_values(method.parameters) send_args = [method.name.inspect, args].reject(&:empty?).join(', ') method_stringifier.stringify(method, "__record__(#{send_args})") end end end bogus-0.1.6/lib/bogus/fakes/fakes_classes.rb0000644000004100000410000000113312454377662021014 0ustar www-datawww-datamodule Bogus class FakesClasses extend Takes takes :creates_fakes_with_stubbed_methods, :overwrites_classes, :overwritten_classes def fake(klass, opts = {}) opts = opts.merge(as: :class) name = opts.delete(:fake_name) || underscore(klass.name.split('::').last).to_sym fake = creates_fakes_with_stubbed_methods.create(name, opts) { klass } overwrites_classes.overwrite(klass.name, fake) overwritten_classes.add(klass.name, klass) end private def underscore(str) str.gsub(/[A-Z]/) { |s| "_" + s.downcase }.gsub(/^_/, '') end end end bogus-0.1.6/lib/bogus/fakes/overwrites_classes.rb0000644000004100000410000000050412454377662022135 0ustar www-datawww-dataclass Bogus::OverwritesClasses def overwrite(full_name, new_klass) modules = full_name.split('::') klass_name = modules.pop parent_module = modules.reduce(Object) { |mod, name| mod.const_get(name) } parent_module.send(:remove_const, klass_name) parent_module.const_set(klass_name, new_klass) end end bogus-0.1.6/lib/bogus/fakes/registers_created_fakes.rb0000644000004100000410000000047212454377662023062 0ustar www-datawww-datamodule Bogus class RegistersCreatedFakes extend Takes takes :creates_fakes, :fake_registry, :double_tracker def create(name, opts = {}, &block) fake = creates_fakes.create(name, opts, &block) fake_registry.store(name, fake) double_tracker.track(fake) fake end end end bogus-0.1.6/lib/bogus/fakes/fake.rb0000644000004100000410000000140512454377662017116 0ustar www-datawww-datamodule Bogus module FakeObject # marker for fake objects end class Fake include RecordInteractions extend RecordInteractions include FakeObject extend FakeObject def initialize(*args) __shadow__ end def to_s "#<#{self.class}:0x#{object_id.to_s(16)}>" end def kind_of?(klass) copied_class = self.class.__copied_class__ super || BaseClassIdentifier.base_class?(copied_class, klass) end alias :instance_of? :kind_of? alias :is_a? :kind_of? class << self alias :__create__ :new def new(*args, &block) value = __record__(:new, *args, &block) return value unless ::Bogus::UndefinedReturnValue.undefined?(value) __create__ end end end end bogus-0.1.6/lib/bogus/fakes/copies_classes.rb0000644000004100000410000000107512454377662021212 0ustar www-datawww-datamodule Bogus class CopiesClasses extend Takes takes :copies_methods def copy(klass) copy_class = Class.new(Bogus::Fake) do define_singleton_method(:__copied_class__) do klass end define_singleton_method(:name) do klass.name end define_singleton_method(:to_s) do klass.name end define_singleton_method(:const_missing) do |name| klass.const_get(name) end end copies_methods.copy(klass, copy_class) copy_class end end end bogus-0.1.6/lib/bogus/fakes/class_methods.rb0000644000004100000410000000072412454377662021043 0ustar www-datawww-datamodule Bogus class ClassMethods extend Takes takes :klass def all klass.methods - Class.methods - bogus_methods end def get(name) klass.method(name) end def remove(name) klass.instance_eval "undef #{name}" end def define(body) klass.instance_eval(body) end private def bogus_methods [:__shadow__, :__reset__, :__overwrite__, :__overwritten_methods__, :__record__] end end end bogus-0.1.6/lib/bogus/fakes/resets_overwritten_classes.rb0000644000004100000410000000045112454377662023702 0ustar www-datawww-datamodule Bogus class ResetsOverwrittenClasses extend Takes takes :overwritten_classes, :overwrites_classes def reset overwritten_classes.classes.each do |name, klass| overwrites_classes.overwrite(name, klass) end overwritten_classes.clear end end end bogus-0.1.6/lib/bogus/fakes/method_stringifier.rb0000644000004100000410000000242512454377662022100 0ustar www-datawww-datamodule Bogus class MethodStringifier def stringify(method, body) <<-RUBY def #{method.name}(#{arguments_as_string(method.parameters)}) #{body} end RUBY end def arguments_as_string(arguments) stringify_arguments(arguments, DefaultValue) end def argument_values(arguments) stringify_arguments(arguments) end private def stringify_arguments(arguments, default = nil) fill_in_missing_names(arguments).map do |type, name| argument_to_string(name, type, default) end.join(', ') end def argument_to_string(name, type, default) case type when :block then "&#{name}" when :key then default ? "#{name}: #{default}" : "#{name}: #{name}" when :keyreq then default ? "#{name}:" : "#{name}: #{name}" when :opt then default ? "#{name} = #{default}" : name when :req then name when :rest then "*#{name}" when :keyrest then "**#{name}" else raise "unknown argument type: #{type}" end end def fill_in_missing_names(arguments) noname_count = 0 arguments.map do |type, name| unless name name = "_noname_#{noname_count}" noname_count += 1 end [type, name] end end end end bogus-0.1.6/lib/bogus/fakes/copies_methods.rb0000644000004100000410000000140312454377662021213 0ustar www-datawww-datamodule Bogus class CopiesMethods extend Takes takes :makes_substitute_methods, :method_copiers, :copies_constructor def copy(from, into) method_copiers.each do |copier| copy_methods(from, into, copier) end copies_constructor.copy(from, into) end private def copy_methods(original_class, copy_class, make_methods) original_methods = make_methods.call(original_class) copy_methods = make_methods.call(copy_class) original_methods.all.each do |name| method = original_methods.get(name) body = method_as_string(method) copy_methods.define(body) end end def method_as_string(method) makes_substitute_methods.stringify(method) end end end bogus-0.1.6/lib/bogus/fakes/makes_ducks.rb0000644000004100000410000000160312454377662020501 0ustar www-datawww-datamodule Bogus class MakesDucks extend Takes takes :method_copiers, :makes_subtypes def make(first_class, *classes) duck = makes_subtypes.make(first_class) classes.each do |klass| method_copiers.each do |copier| remove_methods(copier.call(duck), copier.call(klass)) end end duck end private def remove_methods(duck_methods, klass_methods) not_in_klass = duck_methods.all - klass_methods.all not_in_klass.each { |name| duck_methods.remove(name) } duck_methods.all.each do |name| duck_method = duck_methods.get(name) klass_method = klass_methods.get(name) unless same_interface?(duck_method, klass_method) duck_methods.remove(name) end end end def same_interface?(method1, method2) method1.parameters == method2.parameters end end end bogus-0.1.6/lib/bogus/fakes/creates_fakes_with_stubbed_methods.rb0000644000004100000410000000222012454377662025271 0ustar www-datawww-datamodule Bogus class CreatesFakesWithStubbedMethods extend Takes takes :multi_stubber, :creates_fakes, :responds_to_everything, :fake_configuration def create(name = nil, methods = {}, &block) if name.is_a?(Hash) methods = name name = nil end fake = responds_to_everything unless name fake_opts, methods = split_methods(methods) fake_definition = get_configuration(name, fake_opts, methods, block) fake ||= creates_fakes.create(fake_definition.name, fake_definition.opts, &fake_definition.class_block) multi_stubber.stub_all(fake, fake_definition.stubs) end private def split_methods(methods) fake_args = proc{ |k,_| [:as].include?(k) } [methods.select(&fake_args), methods.reject(&fake_args)] end def get_configuration(name, fake_opts, methods, block) fake = FakeDefinition.new(name: name, opts: fake_opts, stubs: methods, class_block: block) return fake unless fake_configuration.include?(name) configured_fake = fake_configuration.get(name) configured_fake.merge(fake) end end end bogus-0.1.6/lib/bogus/fakes/makes_subtypes.rb0000644000004100000410000000035212454377662021246 0ustar www-datawww-datamodule Bogus class MakesSubtypes extend Takes takes :copies_methods def make(klass) subtype = klass.is_a?(Class) ? Class.new : Module.new copies_methods.copy(klass, subtype) subtype end end end bogus-0.1.6/lib/bogus/fakes/constructor_methods.rb0000644000004100000410000000073712454377662022327 0ustar www-datawww-datamodule Bogus class CopiesConstructor extend Takes takes :method_stringifier, :instance_methods, :class_methods def copy(from, into) return unless from.is_a?(Class) initializer = instance_methods.call(from).get(:initialize) body = body(initializer) class_methods.call(into).define(body) end def body(initializer) body = method_stringifier.stringify(initializer, "super") body.gsub("initialize", "new") end end end bogus-0.1.6/lib/bogus/fakes/base_class_identifier.rb0000644000004100000410000000132412454377662022511 0ustar www-datawww-datamodule Bogus class BaseClassIdentifier extend Takes takes :copied_class, :klass def self.base_class?(copied_class, klass) new(copied_class, klass).base_class? end def base_class? same? || included_module? || subclass? end private def same? klass == copied_class end def included_module? copied_class.included_modules.include?(klass) end def subclass? superclasses.include?(klass) end def superclasses return [] unless copied_class.is_a?(Class) klass = copied_class superclasses = [] while klass superclasses << klass klass = klass.superclass end superclasses end end end bogus-0.1.6/lib/bogus/fakes/instance_methods.rb0000644000004100000410000000053112454377662021536 0ustar www-datawww-datamodule Bogus class InstanceMethods extend Takes takes :klass def all klass.instance_methods - Object.instance_methods end def get(name) klass.instance_method(name) end def remove(name) klass.send(:undef_method, name) end def define(body) klass.class_eval(body) end end end bogus-0.1.6/lib/bogus/fakes/responds_to_everything.rb0000644000004100000410000000044212454377662023013 0ustar www-datawww-datamodule Bogus class RespondsToEverything include FakeObject include RecordInteractions def initialize __shadow__ end def respond_to?(method) true end def method_missing(name, *args, &block) __record__(name, *args, &block) end end end bogus-0.1.6/lib/bogus/fakes/fake_registry.rb0000644000004100000410000000031212454377662021042 0ustar www-datawww-dataclass Bogus::FakeRegistry def initialize @registry = {} end def store(name, object) @registry[object.object_id] = name end def name(object) @registry[object.object_id] end end bogus-0.1.6/lib/bogus/fakes/active_record_accessors.rb0000644000004100000410000000125712454377662023073 0ustar www-datawww-datarequire 'forwardable' module Bogus class ActiveRecordAccessors extend Takes extend Forwardable takes :klass, :instance_methods def_delegators :model_methods, :remove, :define def all return [] unless klass < ActiveRecord::Base return missing_attributes end def get(name) Attribute.new(name) end private def model_methods instance_methods.call(klass) end def all_attributes klass.columns.map(&:name).map(&:to_sym) end def missing_attributes all_attributes - model_methods.all end class Attribute < Struct.new(:name) def parameters [] end end end end bogus-0.1.6/lib/bogus/fakes/converts_name_to_class.rb0000644000004100000410000000120212454377662022735 0ustar www-datawww-datamodule Bogus class ConvertsNameToClass extend Takes class CanNotFindClass < RuntimeError; end takes :search_modules def convert(name) class_name = camelize(name) klass = nil @search_modules.each do |mod| klass = mod.const_get(class_name) rescue nil break if klass end raise CanNotFindClass.new("Can not locate class for name: #{name}") unless klass klass end private def camelize(symbol) string = symbol.to_s string = string.gsub(/_\w/) { |match| match[1].upcase } return string.gsub(/^\w/) { |match| match.upcase } end end end bogus-0.1.6/lib/bogus/fakes/creates_fakes.rb0000644000004100000410000000154212454377662021011 0ustar www-datawww-datamodule Bogus class CreatesFakes class UnknownMode < RuntimeError; end extend Takes takes :copies_classes, :converts_name_to_class, :makes_ducks def create(name, opts = {}, &block) klass = self.klass(name, &block) duck = make_duck(klass) klass_copy = copies_classes.copy(duck) mode = opts.fetch(:as, :instance) case mode when :instance return klass_copy.__create__ when :class return klass_copy else raise UnknownMode.new("Unknown fake creation mode: #{mode}. Allowed values are :instance, :class") end end protected def klass(name, &block) return block.call if block_given? converts_name_to_class.convert(name) end def make_duck(klass) return klass unless klass.is_a?(Array) makes_ducks.make(*klass) end end end bogus-0.1.6/lib/bogus/fakes/overwriten_classes.rb0000644000004100000410000000031412454377662022127 0ustar www-datawww-datamodule Bogus class OverwrittenClasses def add(name, klass) classes << [name, klass] end def clear @classes = [] end def classes @classes ||= [] end end end bogus-0.1.6/lib/bogus/rspec/0000755000004100000410000000000012454377662015706 5ustar www-datawww-databogus-0.1.6/lib/bogus/rspec/extensions.rb0000644000004100000410000000063512454377662020436 0ustar www-datawww-datarequire_relative 'syntax' module Bogus module RSpecExtensions def fake(name, opts = {}, &block) let(name) { fake(name, opts, &block) } end def fake_class(name, opts = {}) before do fake_class(name, opts) end end def verify_contract(name, &block) syntax = RSpecSyntax.new(self) Bogus.add_contract_verification(syntax, name, &block) end end end bogus-0.1.6/lib/bogus/rspec/adapter.rb0000644000004100000410000000037612454377662017661 0ustar www-datawww-datamodule Bogus module RSpecAdapter def setup_mocks_for_rspec # no setup needed end def verify_mocks_for_rspec Bogus.ensure_all_expectations_satisfied! end def teardown_mocks_for_rspec Bogus.clear end end end bogus-0.1.6/lib/bogus/rspec/syntax.rb0000644000004100000410000000102112454377662017553 0ustar www-datawww-datarequire 'forwardable' module Bogus class RSpecSyntax extend Takes extend Forwardable takes :context def_delegators :context, :before, :after, :described_class def described_class=(value) # for new RSpec (> 3.0) context.metadata[:described_class] = value # for old RSpec (< 3.0) context.example.metadata[:example_group][:described_class] = value end def after_suite(&block) RSpec.configure do |config| config.after(:suite, &block) end end end end bogus-0.1.6/lib/bogus/rspec.rb0000644000004100000410000000062112454377662016232 0ustar www-datawww-datarequire 'bogus' RSpec.configure do |config| config.extend Bogus::RSpecExtensions config.include Bogus::MockingDSL config.mock_with Bogus::RSpecAdapter if RSpec::Core::Version::STRING >= "2.14" config.backtrace_exclusion_patterns << Regexp.new("lib/bogus") else config.backtrace_clean_patterns << Regexp.new("lib/bogus") end config.after(:suite) do Bogus.reset! end end bogus-0.1.6/lib/bogus/stubbing/0000755000004100000410000000000012454377662016407 5ustar www-datawww-databogus-0.1.6/lib/bogus/stubbing/undefined_return_value.rb0000644000004100000410000000063212454377662023471 0ustar www-datawww-datamodule Bogus class UndefinedReturnValue def initialize(interaction) @interaction = InteractionPresenter.new(interaction) end def to_s "#" end def method_missing(name, *args, &block) raise NoMethodError, "undefined method '#{name}' for #{self}" end def self.undefined?(value) value.is_a?(self) end end end bogus-0.1.6/lib/bogus/stubbing/anything.rb0000644000004100000410000000020212454377662020547 0ustar www-datawww-datamodule Bogus module Anything def self.==(other) true end def self.inspect "anything" end end end bogus-0.1.6/lib/bogus/stubbing/same_class.rb0000644000004100000410000000026312454377662021047 0ustar www-datawww-datamodule Bogus class SameClass extend Takes takes :klass def inspect "any(#{klass.name})" end def ==(other) other.is_a?(klass) end end end bogus-0.1.6/lib/bogus/stubbing/default_value.rb0000644000004100000410000000005512454377662021554 0ustar www-datawww-datamodule Bogus module DefaultValue end end bogus-0.1.6/lib/bogus/stubbing/record_interactions.rb0000644000004100000410000000031612454377662022774 0ustar www-datawww-datamodule Bogus module RecordInteractions def __shadow__ @__shadow__ ||= Shadow.new end def __record__(method, *args, &block) __shadow__.run(method, *args, &block) end end end bogus-0.1.6/lib/bogus/stubbing/ensures_all_interactions_satisfied.rb0000644000004100000410000000146512454377662026073 0ustar www-datawww-datamodule Bogus class EnsuresAllInteractionsSatisfied def ensure_satisfied!(objects) unsatisfied = unsatisfied_interactions(objects) return if unsatisfied.empty? calls = all_calls(objects) raise NotAllExpectationsSatisfied.create(unsatisfied, calls) end private def unsatisfied_interactions(objects) mapcat_shadows(objects) do |object, shadow| shadow.unsatisfied_interactions.map{|c| [object, c]} end end def all_calls(objects) mapcat_shadows(objects) do |object, shadow| shadow.calls.map{|c| [object, c]} end end def mapcat_shadows(objects, &block) mapped = objects.map do |object| shadow = object.__shadow__ block.call(object, shadow) end mapped.reduce([], :concat) end end end bogus-0.1.6/lib/bogus/stubbing/shadow.rb0000644000004100000410000000272312454377662020225 0ustar www-datawww-datamodule Bogus class Shadow attr_reader :calls def initialize @calls = [] @stubs = [] @required = Set.new end def run(method_name, *args) interaction = Interaction.new(method_name, args) @calls << interaction return_value(interaction) end def has_received(name, args) @calls.any? { |i| Interaction.same?(recorded: i, stubbed: Interaction.new(name, args)) } end def stubs(name, *args, &return_value) interaction = Interaction.new(name, args) add_stub(interaction, return_value) @required.reject! { |i| Interaction.same?(recorded: i, stubbed: interaction) } interaction end def mocks(name, *args, &return_value) interaction = stubs(name, *args, &return_value) @required.add(interaction) end def unsatisfied_interactions @required.reject do |stubbed| @calls.any? do |recorded| Interaction.same?(recorded: recorded, stubbed: stubbed) end end end def self.has_shadow?(object) object.respond_to?(:__shadow__) end private def add_stub(interaction, return_value_block) @stubs << [interaction, return_value_block] if return_value_block end def return_value(interaction) _, return_value = @stubs.reverse.find{|i, v| Interaction.same?(recorded: interaction, stubbed: i)} return_value ||= proc{ UndefinedReturnValue.new(interaction) } return_value.call end end end bogus-0.1.6/lib/bogus/stubbing/interaction_presenter.rb0000644000004100000410000000074112454377662023344 0ustar www-datawww-datamodule Bogus class InteractionPresenter extend Takes takes :interaction def to_s "##{interaction.method}(#{args})#{result}" end private def args interaction.args.map(&:inspect).join(', ') end def result error || return_value end def return_value " => #{interaction.return_value.inspect}" if interaction.has_result end def error " !! #{interaction.error}" if interaction.error end end end bogus-0.1.6/lib/bogus/stubbing/tracks_existence_of_test_doubles.rb0000644000004100000410000000030112454377662025524 0ustar www-datawww-datamodule Bogus class TracksExistenceOfTestDoubles def track(object) doubles << object unless doubles.include?(object) end def doubles @doubles ||= [] end end end bogus-0.1.6/lib/bogus/stubbing/verifies_stub_definition.rb0000644000004100000410000000212712454377662024017 0ustar www-datawww-datamodule Bogus class VerifiesStubDefinition extend Takes takes :method_stringifier def verify!(object, method_name, args) stubbing_non_existent_method!(object, method_name) unless object.respond_to?(method_name) return unless object.methods.include?(method_name) return if WithArguments.with_matcher?(args) method = object.method(method_name) verify_call!(method, args) end private def verify_call!(method, args) object = Object.new fake_method = method_stringifier.stringify(method, "") object.instance_eval(fake_method) object.send(method.name, *args) rescue ArgumentError wrong_arguments!(method, args) end def wrong_arguments!(method, args) args_string = method_stringifier.arguments_as_string(method.parameters) raise ArgumentError, "tried to stub #{method.name}(#{args_string}) with arguments: #{args.map(&:inspect).join(",")}" end def stubbing_non_existent_method!(object, method_name) raise NameError, "#{object.inspect} does not respond to #{method_name}" end end end bogus-0.1.6/lib/bogus/stubbing/overwrites_methods.rb0000644000004100000410000000213012454377662022664 0ustar www-datawww-datamodule Bogus class OverwritesMethods extend Takes takes :makes_substitute_methods def overwrite(object, name) raise "wut?" if name == :__shadow__ return if already_delegates_to_shadow?(object, name) object.extend RecordInteractions object.extend HasOverwritenMethods method = method_by_name(object, name) copy = copy(object, name) object.__overwrite__(name, method, copy) end def reset(object) return if object.is_a?(FakeObject) object.__reset__ end private def already_delegates_to_shadow?(object, name) return false unless object.is_a?(FakeObject) !Fake.instance_methods.include?(name) end def method_by_name(object, name) object.method(name) if object.methods.include?(name) end def copy(object, name) method = method_by_name(object, name) return default_method(name) unless method makes_substitute_methods.stringify(method) end def default_method(name) "def #{name}(*args, &block); __record__(:#{name}, *args, &block); end" end end end bogus-0.1.6/lib/bogus/stubbing/interaction.rb0000644000004100000410000000452712454377662021263 0ustar www-datawww-datamodule Bogus class Interaction < Struct.new(:method, :args, :return_value, :error, :has_result) attr_accessor :arguments def self.same?(opts = {}) InteractionComparator.new(opts).same? end def initialize(method, args, &block) self.method = method self.args = args if block_given? evaluate_return_value(block) self.has_result = true end end private def evaluate_return_value(block) self.return_value = block.call rescue => e self.error = e.class end class InteractionComparator attr_reader :recorded, :stubbed def initialize(opts = {}) @recorded = opts.fetch(:recorded) @stubbed = opts.fetch(:stubbed) end def same? return false unless recorded.method == stubbed.method return false unless same_result? same_args? end private def same_args? ArgumentComparator.new(recorded: recorded.args, stubbed: stubbed.args).same? end def same_result? return true unless recorded.has_result && stubbed.has_result recorded.return_value == stubbed.return_value && recorded.error == stubbed.error end end class ArgumentComparator attr_reader :recorded, :stubbed def initialize(opts = {}) @recorded = opts.fetch(:recorded) @stubbed = opts.fetch(:stubbed) end def same? return true if with_matcher_args? stubbed == recorded_without_defaults end private def recorded_without_defaults without_defaults = recorded.reject{|v| DefaultValue == v} remove_default_keywords(without_defaults) end def remove_default_keywords(recorded) return recorded unless recorded_has_keyword? positional = recorded[0...-1] keyword = recorded.last without_defaults = keyword.reject{|_, v| DefaultValue == v} return positional if without_defaults.empty? positional + [without_defaults] end def with_matcher_args? WithArguments.matches?(stubbed: stubbed, recorded: recorded_without_defaults) end def recorded_has_keyword? last_recorded = recorded.last return false unless last_recorded.is_a?(Hash) last_recorded.values.any? { |v| DefaultValue == v } end end end end bogus-0.1.6/lib/bogus/stubbing/have_received_matcher.rb0000644000004100000410000000345212454377662023234 0ustar www-datawww-datamodule Bogus class HaveReceivedMatcher include ProxiesMethodCalls extend Takes NO_SHADOW = "Given object is not a fake and nothing was ever stubbed or mocked on it!" takes :verifies_stub_definition, :records_double_interactions def matches?(subject) @subject = subject return false unless Shadow.has_shadow?(subject) verifies_stub_definition.verify!(subject, @name, @args) records_double_interactions.record(subject, @name, @args) subject.__shadow__.has_received(@name, @args) end def description "have received #{call_str(@name, @args)}" end def failure_message return NO_SHADOW unless Shadow.has_shadow?(@subject) %Q{Expected #{@subject.inspect} to #{description}, but it didn't.\n\n} + all_calls_str end alias_method :failure_message_for_should, :failure_message def failure_message_when_negated return NO_SHADOW unless Shadow.has_shadow?(@subject) %Q{Expected #{@subject.inspect} not to #{description}, but it did.} end alias_method :failure_message_for_should_not, :failure_message_when_negated def method_call proxy(:set_method) end def build(*args) return method_call if args.empty? set_method(*args) end def set_method(name, *args, &block) @name = name @args = args self end private def call_str(method, args) "#{method}(#{args.map(&:inspect).join(', ')})" end def all_calls_str shadow = @subject.__shadow__ calls = shadow.calls.map{|i| call_str(i.method, i.args)} if calls.any? message = "The recorded interactions were:\n" calls.each{|s| message << " - #{s}\n"} message else "There were no interactions with this object.\n" end end end end bogus-0.1.6/lib/bogus/stubbing/multi_stubber.rb0000644000004100000410000000053412454377662021616 0ustar www-datawww-datamodule Bogus class MultiStubber extend Takes takes :create_double def stub_all(object, methods = {}) double = create_double.call(object) methods.each do |name, result| block = result.is_a?(Proc) ? result : proc{ result } double.stubs(name, Bogus::AnyArgs, &block) end object end end end bogus-0.1.6/lib/bogus/stubbing/matchers/0000755000004100000410000000000012454377662020215 5ustar www-datawww-databogus-0.1.6/lib/bogus/stubbing/matchers/matches_argument.rb0000644000004100000410000000024112454377662024065 0ustar www-datawww-datamodule Bogus class MatchesArgument def initialize(&block) @block = block end def ==(argument) @block.call(argument) end end end bogus-0.1.6/lib/bogus/stubbing/matchers/any_args.rb0000644000004100000410000000020612454377662022343 0ustar www-datawww-datarequire_relative 'with_arguments' module Bogus AnyArgs = WithArguments.new{ true } def AnyArgs.inspect "any_args" end end bogus-0.1.6/lib/bogus/stubbing/matchers/with_arguments.rb0000644000004100000410000000106312454377662023602 0ustar www-datawww-datamodule Bogus class WithArguments attr_reader :predicate def initialize(&predicate) @predicate = predicate end def matches?(args) predicate.call(*args) end def self.matches?(opts = {}) stubbed = opts.fetch(:stubbed) recorded = opts.fetch(:recorded) return false unless with_matcher?(stubbed) return extract(stubbed).matches?(recorded) end def self.with_matcher?(args) args.first.is_a?(WithArguments) end private def self.extract(args) args.first end end end bogus-0.1.6/lib/bogus/stubbing/resets_stubbed_methods.rb0000644000004100000410000000040012454377662023466 0ustar www-datawww-datamodule Bogus class ResetsStubbedMethods extend Takes takes :double_tracker, :overwrites_methods def reset_all_doubles doubles = double_tracker.doubles doubles.each { |double| overwrites_methods.reset(double) } end end end bogus-0.1.6/lib/bogus/stubbing/not_all_expectations_satisfied.rb0000644000004100000410000000136112454377662025206 0ustar www-datawww-datamodule Bogus class NotAllExpectationsSatisfied < StandardError def self.create(unsatisfied_interactions, calls) str = <<-EOF Some of the mocked interactions were not satisfied: <% unsatisfied_interactions.each do |o, i| %> - <%= render_interaction(o, i) %> <% end %> The following calls were recorded: <% calls.each do |o, i| %> - <%= render_interaction(o, i) %> <% end %> EOF str = str.gsub(/ {6}/, '') template = ERB.new(str, nil, "<>") new(template.result(binding)) end def self.render_interaction(object, interaction) args = interaction.args.map(&:inspect).join(", ") "#{object.inspect}.#{interaction.method}(#{args})" end end end bogus-0.1.6/lib/bogus/stubbing/has_overwritten_methods.rb0000644000004100000410000000202112454377662023675 0ustar www-datawww-datarequire 'set' module Bogus module HasOverwritenMethods def self.aliased_name(name) :"__bogus__alias__#{name}" end def self.alias(object, new_name, name) object.singleton_class.send(:alias_method, new_name, name) end def __overwritten_methods__ @__overwritten_methods__ ||= Set.new end def __overwrite__(name, method, body) return if __overwritten_methods__.include?(name) new_name = HasOverwritenMethods.aliased_name(name) HasOverwritenMethods.alias(self, new_name, name) if method __overwritten_methods__ << name instance_eval(body) end def __reset__ __overwritten_methods__.each do |name| new_name = HasOverwritenMethods.aliased_name(name) if respond_to?(new_name) HasOverwritenMethods.alias(self, name, new_name) instance_eval "undef #{new_name}" else instance_eval "undef #{name}" end end @__overwritten_methods__ = nil @__shadow__ = nil end end end bogus-0.1.6/lib/bogus/stubbing/double.rb0000644000004100000410000000137712454377662020216 0ustar www-datawww-datamodule Bogus class Double extend Takes include ProxiesMethodCalls takes :object, :double_tracker, :verifies_stub_definition, :overwrites_methods, :records_double_interactions def stub proxy(:stubs) end def stubs(name, *args, &return_value) verifies_stub_definition.verify!(object, name, args) double_tracker.track(object) records_double_interactions.record(object, name, args, &return_value) overwrites_methods.overwrite(object, name) object.__shadow__.stubs(name, *args, &return_value) end def mock proxy(:mocks) end def mocks(name, *args, &return_value) stubs(name, *args, &return_value) object.__shadow__.mocks(name, *args, &return_value) end end end bogus-0.1.6/lib/bogus/minitest/0000755000004100000410000000000012454377662016426 5ustar www-datawww-databogus-0.1.6/lib/bogus/minitest/spec.rb0000644000004100000410000000112212454377662017701 0ustar www-datawww-datarequire 'bogus/minitest' require_relative 'syntax' module MiniTest::Expectations infect_an_assertion :assert_received, :must_have_received, true infect_an_assertion :refute_received, :wont_have_received, true end class MiniTest::Spec module DSL def fake(name, opts = {}, &block) let(name) { fake(name, opts, &block) } end def fake_class(name, opts = {}) before { fake_class(name, opts) } end def verify_contract(name, &block) syntax = Bogus::MiniTestSyntax.new(self) Bogus.add_contract_verification(syntax, name, &block) end end end bogus-0.1.6/lib/bogus/minitest/syntax.rb0000644000004100000410000000105212454377662020277 0ustar www-datawww-datarequire 'forwardable' module Bogus class MiniTestSyntax extend Takes extend Forwardable takes :context def_delegators :context, :before, :after def described_class return context.desc if context.desc.is_a?(Module) end def described_class=(value) context.instance_variable_set('@desc', value) end def after_suite(&block) # minitest 5 vs 4.7 if defined? Minitest.after_run Minitest.after_run(&block) else MiniTest::Unit.after_tests(&block) end end end end bogus-0.1.6/lib/bogus/takes.rb0000644000004100000410000000020712454377662016225 0ustar www-datawww-datamodule Bogus module Takes def takes(*args) include Dependor::Constructor(*args) attr_reader(*args) end end end bogus-0.1.6/lib/bogus.rb0000644000004100000410000000102612454377662015116 0ustar www-datawww-datarequire 'dependor' require 'erb' require 'set' require_relative 'bogus/takes' require_relative 'bogus/stubbing/record_interactions' require_relative 'bogus/proxies_method_calls' require_relative 'bogus/rspec/extensions' require_relative 'bogus/rspec/adapter' require_relative 'bogus/support' dir = File.realpath File.expand_path('../bogus', __FILE__) Dir["#{dir}/**/*.rb"].sort.each do |path| next if path.include? 'bogus/minitest' next if path.include? 'bogus/rspec' require path end module Bogus extend PublicMethods end bogus-0.1.6/metadata.yml0000644000004100000410000003354012454377662015215 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: bogus version: !ruby/object:Gem::Version version: 0.1.6 platform: ruby authors: - Adam Pohorecki autorequire: bindir: bin cert_chain: [] date: 2015-01-02 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: dependor requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 0.0.4 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 0.0.4 - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: cucumber requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: aruba requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard-rspec requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard-cucumber requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard-ctags-bundler requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: growl requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: libnotify requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: relish requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: coveralls requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: wwtd requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: activerecord requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '3' - - "<" - !ruby/object:Gem::Version version: '5' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '3' - - "<" - !ruby/object:Gem::Version version: '5' - !ruby/object:Gem::Dependency name: activerecord-nulldb-adapter requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: minitest requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '4.7' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '4.7' - !ruby/object:Gem::Dependency name: rb-readline requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.5.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: 0.5.0 description: Decreases the need to write integration tests by ensuring that the things you stub or mock actually exist. email: - adam@pohorecki.pl executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".pelusa.yml" - ".rspec" - ".travis.yml" - Gemfile - Guardfile - Guardfile.cucumber - README.md - Rakefile - bogus.gemspec - features/.nav - features/authors.md - features/changelog.md - features/configuration/fake_ar_attributes.feature - features/configuration/readme.md - features/configuration/search_modules.feature - features/contract_tests/contract_tests_mocks.feature - features/contract_tests/contract_tests_spies.feature - features/contract_tests/contract_tests_stubs.feature - features/contract_tests/custom_overwritten_class.feature - features/contract_tests/readme.md - features/contract_tests/return_value_contracts.feature - features/fakes/anonymous_doubles.feature - features/fakes/duck_types.feature - features/fakes/fake_objects.feature - features/fakes/global_fake_configuration.feature - features/fakes/readme.md - features/fakes/replacing_classes.feature - features/getting_started.md - features/license.md - features/minitest_support.feature - features/readme.md - features/safe_stubbing/argument_matchers.feature - features/safe_stubbing/readme.md - features/safe_stubbing/safe_mocking.feature - features/safe_stubbing/safe_stubbing.feature - features/safe_stubbing/spies.feature - features/step_definitions/rspec_steps.rb - features/support/env.rb - lib/bogus.rb - lib/bogus/configuration.rb - lib/bogus/contracts/adds_contract_verification.rb - lib/bogus/contracts/adds_recording.rb - lib/bogus/contracts/contract_not_fulfilled.rb - lib/bogus/contracts/interactions_repository.rb - lib/bogus/contracts/proxy_class.rb - lib/bogus/contracts/recording_proxy.rb - lib/bogus/contracts/records_double_interactions.rb - lib/bogus/contracts/verifies_contracts.rb - lib/bogus/core_ext.rb - lib/bogus/fake_configuration.rb - lib/bogus/fakes/active_record_accessors.rb - lib/bogus/fakes/base_class_identifier.rb - lib/bogus/fakes/class_methods.rb - lib/bogus/fakes/constructor_methods.rb - lib/bogus/fakes/converts_name_to_class.rb - lib/bogus/fakes/copies_classes.rb - lib/bogus/fakes/copies_methods.rb - lib/bogus/fakes/creates_fakes.rb - lib/bogus/fakes/creates_fakes_with_stubbed_methods.rb - lib/bogus/fakes/fake.rb - lib/bogus/fakes/fake_registry.rb - lib/bogus/fakes/fakes_classes.rb - lib/bogus/fakes/instance_methods.rb - lib/bogus/fakes/makes_ducks.rb - lib/bogus/fakes/makes_substitute_methods.rb - lib/bogus/fakes/makes_subtypes.rb - lib/bogus/fakes/method_stringifier.rb - lib/bogus/fakes/overwriten_classes.rb - lib/bogus/fakes/overwrites_classes.rb - lib/bogus/fakes/registers_created_fakes.rb - lib/bogus/fakes/resets_overwritten_classes.rb - lib/bogus/fakes/responds_to_everything.rb - lib/bogus/injector.rb - lib/bogus/minitest.rb - lib/bogus/minitest/spec.rb - lib/bogus/minitest/syntax.rb - lib/bogus/mocking_dsl.rb - lib/bogus/proxies_method_calls.rb - lib/bogus/public_methods.rb - lib/bogus/rspec.rb - lib/bogus/rspec/adapter.rb - lib/bogus/rspec/extensions.rb - lib/bogus/rspec/syntax.rb - lib/bogus/stubbing/anything.rb - lib/bogus/stubbing/default_value.rb - lib/bogus/stubbing/double.rb - lib/bogus/stubbing/ensures_all_interactions_satisfied.rb - lib/bogus/stubbing/has_overwritten_methods.rb - lib/bogus/stubbing/have_received_matcher.rb - lib/bogus/stubbing/interaction.rb - lib/bogus/stubbing/interaction_presenter.rb - lib/bogus/stubbing/matchers/any_args.rb - lib/bogus/stubbing/matchers/matches_argument.rb - lib/bogus/stubbing/matchers/with_arguments.rb - lib/bogus/stubbing/multi_stubber.rb - lib/bogus/stubbing/not_all_expectations_satisfied.rb - lib/bogus/stubbing/overwrites_methods.rb - lib/bogus/stubbing/record_interactions.rb - lib/bogus/stubbing/resets_stubbed_methods.rb - lib/bogus/stubbing/same_class.rb - lib/bogus/stubbing/shadow.rb - lib/bogus/stubbing/tracks_existence_of_test_doubles.rb - lib/bogus/stubbing/undefined_return_value.rb - lib/bogus/stubbing/verifies_stub_definition.rb - lib/bogus/support.rb - lib/bogus/takes.rb - lib/bogus/version.rb - license.md - pelusa.sh - rbs.sh - spec/bogus/bugs/rbx_instance_eval_bug_spec.rb - spec/bogus/bugs/rbx_jruby_stub_on_class_spec.rb - spec/bogus/clean_ruby_spec.rb - spec/bogus/configuration_spec.rb - spec/bogus/contracts/adds_contract_verification_spec.rb - spec/bogus/contracts/adds_recording_spec.rb - spec/bogus/contracts/interactions_repository_spec.rb - spec/bogus/contracts/proxy_class_spec.rb - spec/bogus/contracts/records_double_interactions_spec.rb - spec/bogus/contracts/verifies_contracts_spec.rb - spec/bogus/fakes/base_class_identifier_spec.rb - spec/bogus/fakes/class_methods_spec.rb - spec/bogus/fakes/converts_name_to_class_spec.rb - spec/bogus/fakes/copies_classes_spec.rb - spec/bogus/fakes/creates_fakes_spec.rb - spec/bogus/fakes/creates_fakes_with_stubbed_methods_spec.rb - spec/bogus/fakes/fake_ar_attributes_spec.rb - spec/bogus/fakes/fake_configuration_spec.rb - spec/bogus/fakes/fake_registry_spec.rb - spec/bogus/fakes/fake_spec.rb - spec/bogus/fakes/fakes_classes_spec.rb - spec/bogus/fakes/faking_factories_spec.rb - spec/bogus/fakes/frozen_fakes_spec.rb - spec/bogus/fakes/instance_methods_spec.rb - spec/bogus/fakes/makes_ducks_spec.rb - spec/bogus/fakes/makes_substitute_methods_spec.rb - spec/bogus/fakes/method_copiers_spec.rb - spec/bogus/fakes/overwriten_classes_spec.rb - spec/bogus/fakes/overwrites_classes_spec.rb - spec/bogus/fakes/registers_created_fakes_spec.rb - spec/bogus/fakes/resets_overwritten_classes_spec.rb - spec/bogus/fakes/stubbing_new_method_on_fake_class_spec.rb - spec/bogus/mocking_dsl_spec.rb - spec/bogus/rspec/syntax_spec.rb - spec/bogus/ruby_2_1_support_spec.rb - spec/bogus/ruby_2_support_spec.rb - spec/bogus/stubbing/anything_spec.rb - spec/bogus/stubbing/double_spec.rb - spec/bogus/stubbing/ensures_all_interactions_satisfied_spec.rb - spec/bogus/stubbing/have_received_matcher_spec.rb - spec/bogus/stubbing/interaction_spec.rb - spec/bogus/stubbing/multi_stubber_spec.rb - spec/bogus/stubbing/overwrites_methods_spec.rb - spec/bogus/stubbing/record_interactions_spec.rb - spec/bogus/stubbing/resets_stubbed_methods_spec.rb - spec/bogus/stubbing/shadow_spec.rb - spec/bogus/stubbing/stubbing_existing_methods_on_fakes_spec.rb - spec/bogus/stubbing/tracks_existence_of_test_doubles_spec.rb - spec/bogus/stubbing/undefined_return_value_spec.rb - spec/bogus/stubbing/verifies_stub_definition_spec.rb - spec/spec_helper.rb - spec/support/fake_creator_of_fakes.rb - spec/support/matchers.rb - spec/support/ruby_features.rb - spec/support/sample_fake.rb - spec/support/shared_examples_for_keyword_arguments.rb homepage: https://github.com/psyho/bogus licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: bogus rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: Create fakes to make your isolated unit tests reliable. test_files: [] bogus-0.1.6/.pelusa.yml0000644000004100000410000000002512454377662014774 0ustar www-datawww-datasources: lib/**/*.rb bogus-0.1.6/.gitignore0000644000004100000410000000015412454377662014675 0ustar www-datawww-data*.gem .bundle .rbx .ruby-gemset .ruby-version .rvmrc coverage/ Gemfile.lock gems.tags pkg/* tags tags tmp/* bogus-0.1.6/README.md0000644000004100000410000000546012454377662014171 0ustar www-datawww-data# Bogus Bogus aims to make your unit tests more reliable by ensuring that you don't stub or mock methods that don't actually exist in the mocked objects. [![build status](https://secure.travis-ci.org/psyho/bogus.png)](http://travis-ci.org/psyho/bogus) [![Code Climate](https://codeclimate.com/github/psyho/bogus.png)](https://codeclimate.com/github/psyho/bogus) [![Coverage Status](https://coveralls.io/repos/psyho/bogus/badge.png?branch=master)](https://coveralls.io/r/psyho/bogus?branch=master) [![Gem Version](https://badge.fury.io/rb/bogus.png)](http://badge.fury.io/rb/bogus) [![Dependency Status](https://gemnasium.com/psyho/bogus.png)](https://gemnasium.com/psyho/bogus) [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/9908a24d18bc26923a8ab08c28fcc8e5 "githalytics.com")](http://githalytics.com/psyho/bogus) ## Example ```ruby class PostRepository def store(title) # save a new post in the database end end class PostAdder < Struct.new(:post_repository) def add(title) post = post_repository.store(title) # do some stuff with the post end end require 'bogus/rspec' describe PostAdder do fake(:post_repository) it "stores the post" do post_adder = PostAdder.new(post_repository) post_adder.add("Bogus is safe!") expect(post_repository).to have_received.store("Bogus is safe!") end end ``` ## Features * [Safe Stubbing][safe-stubbing] - Bogus does not allow you to stub methods that don't exist or don't match the stubbed signature. * [Fakes][fakes] - test doubles that have the same interface as the doubled class. * [Support for ActiveRecord models][ar-support] - Bogus comes with support for active record fields out of the box. * [Global fake configuration][global-configuration] - Decouple your fakes from class names and define default return values in one place. * [Contract tests][contract-tests] - a unique feature of Bogus, which reduces the need for integrated tests to a minimum by ensuring that the things you stub match how the object really behaves. ## Documentation [You can find more detailed (and executable) documentation on Relish.][docs] ## License MIT. See the [LICENSE file][license]. ## Authors * [Adam Pohorecki](http://github.com/psyho) * [Paweł Pierzchała](http://github.com/wrozka) * [Piotr Szotkowski](https://github.com/chastell) * [Marek Nowak](https://github.com/yundt) [docs]: http://www.relishapp.com/bogus/bogus/docs [safe-stubbing]: https://www.relishapp.com/bogus/bogus/docs/safe-stubbing [fakes]: https://www.relishapp.com/bogus/bogus/docs/fakes [ar-support]: https://www.relishapp.com/bogus/bogus/docs/configuration/fake-ar-attributes [global-configuration]: https://www.relishapp.com/bogus/bogus/docs/fakes/global-fake-configuration [contract-tests]: https://www.relishapp.com/bogus/bogus/docs/contract-tests [license]: features/license.md bogus-0.1.6/Guardfile.cucumber0000644000004100000410000000054712454377662016344 0ustar www-datawww-data# A sample Guardfile # More info at https://github.com/guard/guard#readme guard 'cucumber' do watch(%r{^features/.+\.feature$}) watch(%r{^features/support/.+$}) { 'features' } watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' } watch(%r{^lib/(.+)\.rb$}) { 'features' } end bogus-0.1.6/Guardfile0000644000004100000410000000064212454377662014534 0ustar www-datawww-data# A sample Guardfile # More info at https://github.com/guard/guard#readme guard 'rspec', cmd: 'bundle exec rspec', all_after_pass: true, all_on_start: true do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { "spec" } end guard 'ctags-bundler', :src_path => ["lib", "spec"] do watch(/^(lib|spec)\/.*\.rb$/) watch('Gemfile.lock') end