Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

getting unit tests around the command infrastructure

  • Loading branch information...
commit cd74fe96c35c31bbcc5b59e16985cfebbb6effbd 1 parent 85eb816
@lgleasain lgleasain authored
View
4 Gemfile
@@ -3,11 +3,13 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in passbook.gemspec
gem 'rubyzip'
gem 'grocer'
+gem 'commander'
+gem 'terminal-table'
group :test, :development do
gem 'rack-test'
gem 'activesupport'
- gem 'jeweler'
+ gem 'jeweler', :git => 'git://github.com/foxnewsnetwork/jeweler.git', :branch => 'ruby-2.0.0-ifying'
gem 'simplecov'
gem 'rspec'
gem 'rake'
View
62 Gemfile.lock
@@ -1,41 +1,51 @@
+GIT
+ remote: git://github.com/foxnewsnetwork/jeweler.git
+ revision: f05c62e168cfc29bd82cebe06df8fd11e1ef09ee
+ branch: ruby-2.0.0-ifying
+ specs:
+ jeweler (1.8.4)
+ bundler (~> 1.3.0.pre)
+ git (>= 1.2.5)
+ rake
+ rdoc
+
GEM
remote: https://rubygems.org/
specs:
- activesupport (3.2.8)
- i18n (~> 0.6)
+ activesupport (3.2.13)
+ i18n (= 0.6.1)
multi_json (~> 1.0)
- diff-lcs (1.1.3)
+ commander (4.1.3)
+ highline (~> 1.6.11)
+ diff-lcs (1.2.4)
git (1.2.5)
- grocer (0.3.0)
+ grocer (0.3.4)
+ highline (1.6.18)
i18n (0.6.1)
- jeweler (1.8.4)
- bundler (~> 1.0)
- git (>= 1.2.5)
- rake
- rdoc
- json (1.7.5)
- json (1.7.5-java)
- multi_json (1.3.6)
- rack (1.4.1)
+ json (1.7.7)
+ json (1.7.7-java)
+ multi_json (1.7.2)
+ rack (1.5.2)
rack-test (0.6.2)
rack (>= 1.0)
- rake (0.9.2.2)
- rdoc (3.12)
+ rake (10.0.4)
+ rdoc (4.0.1)
json (~> 1.4)
- rspec (2.11.0)
- rspec-core (~> 2.11.0)
- rspec-expectations (~> 2.11.0)
- rspec-mocks (~> 2.11.0)
- rspec-core (2.11.1)
- rspec-expectations (2.11.3)
- diff-lcs (~> 1.1.3)
- rspec-mocks (2.11.3)
+ rspec (2.13.0)
+ rspec-core (~> 2.13.0)
+ rspec-expectations (~> 2.13.0)
+ rspec-mocks (~> 2.13.0)
+ rspec-core (2.13.1)
+ rspec-expectations (2.13.0)
+ diff-lcs (>= 1.1.3, < 2.0)
+ rspec-mocks (2.13.1)
rubyzip (0.9.9)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
- yard (0.8.3)
+ terminal-table (1.4.5)
+ yard (0.8.6.1)
PLATFORMS
java
@@ -43,11 +53,13 @@ PLATFORMS
DEPENDENCIES
activesupport
+ commander
grocer
- jeweler
+ jeweler!
rack-test
rake
rspec
rubyzip
simplecov
+ terminal-table
yard
View
1  Rakefile
@@ -19,6 +19,7 @@ Jeweler::Tasks.new do |gem|
gem.description = %Q{This gem allows you to create IOS Passbooks. Unlike some, this works with Rails but does not require it.}
gem.email = ['thomas@lauro.fr', 'lgleason@polyglotprogramminginc.com']
gem.authors = ['Thomas Lauro', 'Lance Gleason']
+ gem.executables = ['pk']
# dependencies defined in Gemfile
end
Jeweler::RubygemsDotOrgTasks.new
View
21 bin/pk
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+
+require 'commander/import'
+require 'terminal-table'
+
+$:.push File.expand_path("../../lib", __FILE__)
+require 'passbook'
+
+HighLine.track_eof = false # Fix for built-in Ruby
+Signal.trap("INT") {} # Suppress backtrace when exiting command
+
+program :version, '0.1'
+program :description, 'A command-line interface for generating and previewing passbook passes'
+
+program :help, 'Author', 'Thomas Lauro <>, Lance Gleason <lgleason@polyglotprogramminginc.com>'
+program :help, 'Website', 'https://github.com/frozon/passbook'
+program :help_formatter, :compact
+
+default_command :help
+
+require 'passbook/commands'
View
62 lib/commands/build.rb
@@ -0,0 +1,62 @@
+command :build do |c|
+ c.syntax = 'pk build [PASSNAME]'
+ c.summary = 'Creates a .pkpass archive'
+ c.description = ''
+
+ c.example 'description', 'pk archive mypass -o mypass.pkpass'
+ c.option '-w', '--wwdc_certificate /path/to/wwdc_cert.pem', 'Pass certificate'
+ c.option '-k', '--p12_key /path/to/cert.p12'
+ c.option '-c', '--p12_certificate /path/to/cert.p12'
+ c.option '-p', '--password password', 'certificate password'
+ c.option '-o', '--output /path/to/out.pkpass', '.pkpass output filepath'
+
+ c.action do |args, options|
+ determine_directory! unless @directory = args.first
+ validate_directory!
+
+ @filepath = options.output || "#{@directory}.pkpass"
+ validate_output_filepath!
+
+ @certificate = options.wwdc_certificate
+ validate_certificate!
+
+ @password = (options.password ? options.password : (ask("Enter certificate password:"){|q| q.echo = false}))
+
+ Passbook.configure do |passbook|
+ passbook.wwdc_cert = @certificate
+ passbook.p12_key = options.p12_key
+ passbook.p12_certificate = options.p12_certificate
+ passbook.p12_password = @password
+ end
+
+ assets = Dir[File.join(@directory, '*')]
+ pass_json = File.read(assets.delete(assets.detect{|file| File.basename(file) == 'pass.json'}))
+ pass = Passbook::PKPass.new(pass_json)
+ pass.addFiles assets
+
+ begin
+ pass_stream = pass.stream
+ pass_string = pass_stream.string
+
+ File.open(@filepath, 'w') do |f|
+ f.write pass_string
+ end
+ rescue OpenSSL::PKCS12::PKCS12Error => error
+ say_error "Error: #{error.message}"
+ say_warning "You may be getting this error because the certificate password is either incorrect or missing"
+ abort
+ rescue => error
+ say_error "Error: #{error.message}" and abort
+ end
+ end
+end
+
+alias_command :archive, :build
+alias_command :b, :build
+
+private
+
+def validate_output_filepath!
+ say_error "Filepath required" and abort if @filepath.nil? or @filepath.empty?
+ say_error "#{@filepath} already exists" and abort if File.exist?(@filepath)
+end
View
26 lib/commands/commands.rb
@@ -0,0 +1,26 @@
+$:.push File.expand_path('../', __FILE__)
+
+require 'commands/build'
+require 'commands/generate'
+#require 'commands/serve'
+private
+
+def determine_directory!
+ files = Dir['*/pass.json']
+ @directory ||= case files.length
+ when 0 then nil
+ when 1 then File.dirname(files.first)
+ else
+ @directory = choose "Select a directory:", *files.collect{|f| File.dirname(f)}
+ end
+end
+
+def validate_directory!
+ say_error "Missing argument" and abort if @directory.nil?
+ say_error "Directory #{@directory} does not exist" and abort unless File.directory?(@directory)
+ say_error "Directory #{@directory} is not a valid pass" and abort unless File.exist?(File.join(@directory, "pass.json"))
+end
+
+def validate_certificate!
+ say_error "Missing or invalid certificate file" and abort if @certificate.nil? or not File.exist?(@certificate)
+end
View
45 lib/commands/generate.rb
@@ -0,0 +1,45 @@
+require 'fileutils'
+
+command :generate do |c|
+ c.syntax = 'pk generate PASSNAME'
+ c.summary = 'Generates a template pass directory'
+ c.description = ''
+
+ c.example 'description', 'pk generate mypass'
+ c.option '-T', '--type [boardingPass|coupon|eventTicket|storeCard|generic]', 'Type of pass'
+
+ c.action do |args, options|
+ @directory = args.first
+ @directory ||= ask "Enter a passbook name: "
+
+ say_error "Missing pass name" and abort if @directory.nil? or @directory.empty?
+ say_error "Directory #{@directory} already exists" and abort if File.directory?(@directory)
+ say_error "File exists at #{@directory}" and abort if File.exist?(@directory)
+
+ @type = options.type
+ #determine_type! unless @type
+ #validate_type!
+
+ FileUtils.mkdir_p @directory
+ FileUtils.cp File.join(File.dirname(__FILE__), '..', 'templates', "#{@type}.json"), File.join(@directory, 'pass.json')
+ ['icon.png', 'icon@2x.png'].each do |file|
+ FileUtils.touch File.join(@directory, file)
+ end
+
+ say_ok "Pass generated in #{@directory}"
+ end
+end
+
+alias_command :new, :generate
+alias_command :g, :generate
+
+private
+
+def determine_type!
+ @type ||= choose "Select a pass type", *Dubai::Passbook::Pass::TYPES
+end
+
+def validate_type!
+ say_error %{Invalid type: "#{@type}", expected one of: [#{Dubai::Passbook::Pass::TYPES.join(', ')}]} unless Dubai::Passbook::Pass::TYPES.include?(@type)
+end
+
View
56 lib/commands/templates/boarding-pass.json
@@ -0,0 +1,56 @@
+{
+ "formatVersion" : 1,
+ "passTypeIdentifier" : "pass.com.example.boarding-pass",
+ "description" : "Example Boarding Pass",
+ "teamIdentifier": "Example",
+ "organizationName": "Example",
+ "serialNumber" : "123456",
+ "foregroundColor": "#866B23",
+ "backgroundColor": "#FFD248",
+ "boardingPass" : {
+ "primaryFields" : [
+ {
+ "key" : "origin",
+ "label" : "San Francisco",
+ "value" : "SFO"
+ },
+ {
+ "key" : "destination",
+ "label" : "London",
+ "value" : "LHR"
+ }
+ ],
+ "secondaryFields" : [
+ {
+ "key" : "boarding-gate",
+ "label" : "Gate",
+ "value" : "F12"
+ }
+ ],
+ "auxiliaryFields" : [
+ {
+ "key" : "seat",
+ "label" : "Seat",
+ "value" : "7A"
+ },
+ {
+ "key" : "passenger-name",
+ "label" : "Passenger",
+ "value" : "John Appleseed"
+ }
+ ],
+ "transitType" : "PKTransitTypeAir",
+ "barcode" : {
+ "message" : "ABC123",
+ "format" : "PKBarcodeFormatQR",
+ "messageEncoding" : "iso-8859-1"
+ },
+ "backFields" : [
+ {
+ "key" : "terms",
+ "label" : "Terms and Conditions",
+ "value" : "Lorem ipsum dolar sit amet"
+ }
+ ]
+ }
+}
View
17 passbook.gemspec
@@ -9,9 +9,10 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Thomas Lauro", "Lance Gleason"]
- s.date = "2013-03-08"
+ s.date = "2013-05-05"
s.description = "This gem allows you to create IOS Passbooks. Unlike some, this works with Rails but does not require it."
s.email = ["thomas@lauro.fr", "lgleason@polyglotprogramminginc.com"]
+ s.executables = ["pk"]
s.extra_rdoc_files = [
"LICENSE",
"README.md"
@@ -24,9 +25,13 @@ Gem::Specification.new do |s|
"README.md",
"Rakefile",
"VERSION",
+ "bin/pk",
"lib/passbook.rb",
+ "lib/passbook/commands.rb",
+ "lib/passbook/commands/generate.rb",
"lib/passbook/pkpass.rb",
"lib/passbook/push_notification.rb",
+ "lib/passbook/templates/boarding-pass.json",
"lib/passbook/version.rb",
"lib/rack/passbook_rack.rb",
"lib/rails/generators/passbook/config/config_generator.rb",
@@ -44,15 +49,17 @@ Gem::Specification.new do |s|
s.homepage = "http://github.com/frozon/passbook"
s.licenses = ["MIT"]
s.require_paths = ["lib"]
- s.rubygems_version = "1.8.24"
+ s.rubygems_version = "2.0.3"
s.summary = "A IOS Passbook generator."
if s.respond_to? :specification_version then
- s.specification_version = 3
+ s.specification_version = 4
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<rubyzip>, [">= 0"])
s.add_runtime_dependency(%q<grocer>, [">= 0"])
+ s.add_runtime_dependency(%q<commander>, [">= 0"])
+ s.add_runtime_dependency(%q<terminal-table>, [">= 0"])
s.add_development_dependency(%q<rack-test>, [">= 0"])
s.add_development_dependency(%q<activesupport>, [">= 0"])
s.add_development_dependency(%q<jeweler>, [">= 0"])
@@ -63,6 +70,8 @@ Gem::Specification.new do |s|
else
s.add_dependency(%q<rubyzip>, [">= 0"])
s.add_dependency(%q<grocer>, [">= 0"])
+ s.add_dependency(%q<commander>, [">= 0"])
+ s.add_dependency(%q<terminal-table>, [">= 0"])
s.add_dependency(%q<rack-test>, [">= 0"])
s.add_dependency(%q<activesupport>, [">= 0"])
s.add_dependency(%q<jeweler>, [">= 0"])
@@ -74,6 +83,8 @@ Gem::Specification.new do |s|
else
s.add_dependency(%q<rubyzip>, [">= 0"])
s.add_dependency(%q<grocer>, [">= 0"])
+ s.add_dependency(%q<commander>, [">= 0"])
+ s.add_dependency(%q<terminal-table>, [">= 0"])
s.add_dependency(%q<rack-test>, [">= 0"])
s.add_dependency(%q<activesupport>, [">= 0"])
s.add_dependency(%q<jeweler>, [">= 0"])
View
14 spec/lib/commands/build_spec.rb
@@ -0,0 +1,14 @@
+require 'lib/commands/commands_spec_helper'
+
+describe 'Build' do
+
+ before :each do
+ program :version, '1.2.3'
+ program :description, "Honey Badger Don't Care"
+ $stderr = StringIO.new
+ mock_terminal
+ end
+
+ specify "" do
+ end
+end
View
102 spec/lib/commands/commands_spec.rb
@@ -0,0 +1,102 @@
+require 'lib/commands/commands_spec_helper'
+
+describe 'Commands' do
+
+ before :each do
+ program :version, '1.2.3'
+ program :description, "Honey Badger Don't Care"
+ end
+
+ context 'determine directory' do
+
+ specify 'no directories' do
+ Dir.should_receive(:[]).and_return []
+ determine_directory!
+ @directory.should eq nil
+ end
+
+ specify 'one directory present' do
+ Dir.should_receive(:[]).and_return ['ass']
+ File.should_receive(:dirname).with('ass').and_return('/honey/badger/is/bad/ass')
+ determine_directory!
+ @directory.should eq '/honey/badger/is/bad/ass'
+ end
+
+ specify 'multiple directories' do
+ Dir.should_receive(:[]).and_return ['cobras', 'bee_larvae']
+ File.should_receive(:dirname).with('cobras').and_return('/yummy/cobras')
+ File.should_receive(:dirname).with('bee_larvae').and_return('/disgusting/bee_larvae')
+ self.should_receive(:choose).with('Select a directory:',
+ '/yummy/cobras', '/disgusting/bee_larvae').and_return '/yummy/cobras'
+ determine_directory!
+ @directory.should eq '/yummy/cobras'
+ end
+
+ end
+
+ context 'validate directory' do
+
+ specify 'missing directory' do
+ self.should_receive(:say_error).with('Missing argument').and_return true
+ lambda {
+ @directory = nil
+ validate_directory!
+ }.should exit_with_code(1)
+ end
+
+ specify 'directory does not exist' do
+ self.should_receive(:say_error).with("Directory scraps does not exist").and_return true
+ File.should_receive(:directory?).with('scraps').and_return false
+ lambda {
+ @directory = 'scraps'
+ validate_directory!
+ }.should exit_with_code(1)
+ end
+
+ specify 'directory does not have a valid pass' do
+ self.should_receive(:say_error).with("Directory scraps is not a valid pass").and_return true
+ File.should_receive(:directory?).with('scraps').and_return true
+ File.should_receive(:exist?).with('scraps/pass.json').and_return false
+ lambda {
+ @directory = 'scraps'
+ validate_directory!
+ }.should exit_with_code(1)
+ end
+
+ specify 'directory has valid pass' do
+ File.should_receive(:directory?).with('scraps').and_return true
+ File.should_receive(:exist?).with('scraps/pass.json').and_return true
+ lambda {
+ @directory = 'scraps'
+ validate_directory!
+ }.should_not exit_with_code(1)
+ end
+ end
+
+ context 'validate certificate' do
+ specify 'nil certificate' do
+ self.should_receive(:say_error).with("Missing or invalid certificate file").and_return true
+ lambda {
+ @certificate = nil
+ validate_certificate!
+ }.should exit_with_code(1)
+ end
+
+ specify 'certificate file does not exist' do
+ self.should_receive(:say_error).with("Missing or invalid certificate file").and_return true
+ File.should_receive(:exist?).with('jackels').and_return false
+ lambda {
+ @certificate = 'jackels'
+ validate_certificate!
+ }.should exit_with_code(1)
+ end
+
+ specify 'certificate file exists' do
+ File.should_receive(:exist?).with('jackels').and_return true
+ lambda {
+ @certificate = 'jackels'
+ validate_certificate!
+ }.should_not exit_with_code(1)
+ end
+ end
+end
View
51 spec/lib/commands/commands_spec_helper.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+require 'terminal-table'
+require 'commander/import'
+
+Dir['lib/commands/**/*.rb'].each {|f| require File.join(File.dirname(__FILE__), '../../..', f.gsub(/.rb/, ''))}
+
+def mock_terminal
+ @input = StringIO.new
+ @output = StringIO.new
+ $terminal = HighLine.new @input, @output
+end
+
+def new_command_runner *args, &block
+ Commander::Runner.instance_variable_set :"@singleton", Commander::Runner.new(args)
+ program :name, 'test'
+ program :version, '1.2.3'
+ program :description, 'something'
+ create_test_command
+ yield if block
+ Commander::Runner.instance
+end
+
+def run *args
+ new_command_runner(*args) do
+ program :help_formatter, Commander::HelpFormatter::Base
+ end.run!
+ @output.string
+end
+
+RSpec::Matchers.define :exit_with_code do |exp_code|
+ actual = nil
+ match do |block|
+ begin
+ block.call
+ rescue SystemExit => e
+ actual = e.status
+ end
+ actual and actual == exp_code
+ end
+ failure_message_for_should do |block|
+ "expected block to call exit(#{exp_code}) but exit" +
+ (actual.nil? ? " not called" : "(#{actual}) was called")
+ end
+ failure_message_for_should_not do |block|
+ "expected block not to call exit(#{exp_code})"
+ end
+ description do
+ "expect block to call exit(#{exp_code})"
+ end
+end
+
Please sign in to comment.
Something went wrong with that request. Please try again.