Permalink
Browse files

Initial commit of the UISpecRunner

  • Loading branch information...
0 parents commit a4bd7a4fdfc5be1010d7cd836eaa1cab2a32d8f8 Blake Watters committed Jul 15, 2010
Showing with 371 additions and 0 deletions.
  1. +21 −0 .gitignore
  2. +20 −0 LICENSE
  3. +17 −0 README.rdoc
  4. +45 −0 Rakefile
  5. +4 −0 bin/uispec
  6. +109 −0 lib/uispecrunner.rb
  7. +37 −0 lib/uispecrunner/application.rb
  8. +93 −0 lib/uispecrunner/options.rb
  9. +8 −0 spec/options_spec.rb
  10. +1 −0 spec/spec.opts
  11. +9 −0 spec/spec_helper.rb
  12. +7 −0 spec/uispecrunner_spec.rb
@@ -0,0 +1,21 @@
+## MAC OS
+.DS_Store
+
+## TEXTMATE
+*.tmproj
+tmtags
+
+## EMACS
+*~
+\#*
+.\#*
+
+## VIM
+*.swp
+
+## PROJECT::GENERAL
+coverage
+rdoc
+pkg
+
+## PROJECT::SPECIFIC
20 LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2009 Blake Watters
+
+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.
@@ -0,0 +1,17 @@
+= UISpecRunner
+
+Description goes here.
+
+== Note on Patches/Pull Requests
+
+* Fork the project.
+* Make your feature addition or bug fix.
+* Add tests for it. This is important so I don't break it in a
+ future version unintentionally.
+* Commit, do not mess with rakefile, version, or history.
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
+* Send me a pull request. Bonus points for topic branches.
+
+== Copyright
+
+Copyright (c) 2010 Blake Watters. See LICENSE for details.
@@ -0,0 +1,45 @@
+require 'rubygems'
+require 'rake'
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |gem|
+ gem.name = "UISpecRunner"
+ gem.summary = %Q{Flexible spec runner for UISpec on iOS}
+ gem.description = %Q{Provides a simple Ruby interface for running UISpec iPhone tests}
+ gem.email = "blake@twotoasters.com"
+ gem.homepage = "http://github.com/twotoasters/UISpecRunner"
+ gem.authors = ["Blake Watters"]
+ gem.add_development_dependency "rspec", ">= 1.2.9"
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
+ end
+ Jeweler::GemcutterTasks.new
+rescue LoadError
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
+end
+
+require 'spec/rake/spectask'
+Spec::Rake::SpecTask.new(:spec) do |spec|
+ spec.libs << 'lib' << 'spec'
+ spec.spec_files = FileList['spec/**/*_spec.rb']
+end
+
+Spec::Rake::SpecTask.new(:rcov) do |spec|
+ spec.libs << 'lib' << 'spec'
+ spec.pattern = 'spec/**/*_spec.rb'
+ spec.rcov = true
+end
+
+task :spec => :check_dependencies
+
+task :default => :spec
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "UISpecRunner #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+require 'uispecrunner/application'
+exit UISpecRunner::Application.run!(*ARGV)
@@ -0,0 +1,109 @@
+# UISpec Runner
+# By: Blake Watters <blake@twotoasters.com>
+# Portions borrowed from Eloy Duran's Kicker script (http://github.com/alloy/UISpec)
+#
+# Find the SDK versions (auto-prefer 4.0, then 3.0?)
+# Create a rake file...
+# Detect the project name?
+# Use IO.popen to show the output in real time?
+
+require 'tmpdir'
+
+class UISpecRunner
+ attr_accessor :project, :target, :configuration, :sdk_version, :build_dir, :verbose
+
+ # private
+ attr_accessor :run_mode, :class_name, :method_name, :protocol_name
+
+ def initialize(options = {})
+ options.each { |k,v| self.send("#{k}=", v) }
+ self.sdk_version ||= '3.0'
+ self.target ||= 'UISpec'
+ self.configuration ||= 'Debug'
+ self.build_dir ||= './build'
+ self.run_mode ||= :all
+ end
+
+ def run!
+ # TODO: Do the right thing based on command
+ case run_mode
+ when :all
+ run_all!
+ when :class
+ run_class!(self.class_name)
+ when :method
+ run_class_method!(self.class_name, self.method_name)
+ when :protocol
+ run_protocol!(self.protocol_name)
+ else
+ raise ArgumentError, "Unknown run mode: #{run_mode}"
+ end
+ end
+
+ def run_all!
+ run_specs
+ end
+
+ def run_protocol!(protocol_name)
+ run_specs('UISPEC_PROTOCOL' => protocol_name)
+ end
+
+ def run_class!(class_name)
+ run_specs('UISPEC_CLASS' => class_name)
+ end
+
+ def run_class_method!(class_name, method_name)
+ run_specs('UISPEC_CLASS' => class_name, 'UISPEC_METHOD' => method_name)
+ end
+
+ def verbose?
+ self.verbose
+ end
+
+ private
+ def run_specs(env = {})
+ if build_project!
+ with_env('DYLD_ROOT_PATH' => sdk_dir, 'IPHONE_SIMULATOR_ROOT' => sdk_dir, 'CFFIXED_USER_HOME' => tmpdir) do
+ command = "#{build_dir}/Debug-iphonesimulator/#{target}.app/#{target} -RegisterForSystemEvents"
+ puts "Executing: #{command}" if verbose?
+ system command
+ end
+ else
+ puts "[!] Failed to build UISpecs.app"
+ end
+ end
+
+ def sdk_dir
+ "/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator#{sdk_version}.sdk"
+ end
+
+ def tmpdir
+ Dir.tmpdir
+ end
+
+ def project_switch
+ "-project #{project}" if project
+ end
+
+ def build_project!
+ command = "xcodebuild #{project_switch} -target #{target} -configuration #{configuration} -sdk #{sdk_dir} > /dev/null"
+ puts "Building project with: #{command}" if verbose?
+ system(command)
+ end
+
+ def find_first_project
+ # TODO
+ end
+
+ def find_latest_sdk
+ # TODO
+ end
+
+ def with_env(env)
+ before = env.inject({}) { |h, (k, _)| h[k] = ENV[k]; h }
+ env.each { |k, v| ENV[k] = v }
+ yield
+ ensure
+ before.each { |k, v| ENV[k] = v }
+ end
+end
@@ -0,0 +1,37 @@
+# -e - Executes a single spec by method name
+# -c - Executes all specs in a given class
+# -p - Execute all specs on a class conforming to a specific protocol
+# -sdk - Set the SDK version
+# -project= - Set the project
+# -latest-sdk - Detect the latest SDK
+#
+# TODO: Should be able to install a Rake file
+# TODO: Should be able to install a main.m runner file.
+require 'uispecrunner'
+require 'uispecrunner/options'
+
+class UISpecRunner
+ class Application
+ def self.run!(*arguments)
+ # TODO: Parse the options
+ # TODO: Instantiate the app and run...
+ options = UISpecRunner::Options.new(arguments)
+
+ if options[:invalid_argument]
+ $stderr.puts options[:invalid_argument]
+ options[:show_help] = true
+ end
+
+ if options[:show_help]
+ $stderr.puts options.opts
+ return 1
+ end
+
+ # puts "Arguments are: #{options.opts}"
+ # exit 1
+ runner = UISpecRunner.new(options)
+ runner.run!
+ return 0
+ end
+ end
+end
@@ -0,0 +1,93 @@
+class UISpecRunner
+ class Options < Hash
+ attr_reader :opts, :orig_args
+
+ def initialize(args)
+ super()
+
+ @orig_args = args.clone
+
+ self[:target] = 'UISpec'
+ self[:configuration] = 'Debug'
+ self[:build_dir] = './build'
+
+ require 'optparse'
+ @opts = OptionParser.new do |o|
+ o.banner = "Usage: #{File.basename($0)} [options]\ne.g. #{File.basename($0)}"
+
+ # Configure default settings
+ self[:run_mode] = :all
+ self[:target] = 'UISpec'
+ self[:configuration] = 'Debug'
+ self[:build_dir] = './build'
+ self[:verbose] = false
+
+ o.separator ""
+ o.separator "Run Modes:"
+
+ o.on('-c', '--class [CLASS]', 'Run the specified UISpec class') do |class_name|
+ self[:class_name] = class_name
+ self[:run_mode] = :class
+ end
+
+ o.on('-m', '--method [METHOD]', 'Run the specified spec method') do |method|
+ self[:method_name] = method
+ self[:run_mode] = :class
+ # TODO: Need to raise exception if method is specified without class
+ end
+
+ o.on('-p', '--protocol [PROTOCOL]', 'Run all UISpec classes implementing the Objective-C protocol') do |protocol|
+ self[:protocol_name] = protocol
+ self[:run_mode] = :protocol
+ end
+
+ o.separator ""
+ o.separator "Environment options:"
+
+ o.on('--project [PROJECT_FILE]', 'Run the UISpec target in specified project') do |project|
+ self[:project] = project
+ end
+
+ o.on('--sdk [VERSION]',
+ 'Run the UISpec target against the iPhone SDK version',
+ 'Default: 3.0') do |sdk_version|
+ self[:sdk_version] = sdk_version
+ end
+
+ o.on('--configuration [CONFIGURATION]',
+ 'Build with specified XCode configuration.',
+ 'Default: Debug') do |configuration|
+ self[:configuration] = configuration
+ end
+
+ o.on('--target [TARGET]',
+ 'Run the specified XCode target.',
+ 'Default: UISpec') do |target|
+ self[:target] = target
+ end
+
+ o.on('--builddir [BUILD_DIR]',
+ 'Run app in the build directory.',
+ 'Default: ./build') do |build_dir|
+ self[:build_dir] = build_dir
+ end
+
+ o.on('-v', '--[no-]verbose', "Run verbosely") do |v|
+ self[:verbose] = v
+ end
+
+ o.on_tail('-h', '--help', 'display this help and exit') do
+ self[:show_help] = true
+ end
+ end
+
+ begin
+ @opts.parse!(args)
+ # TODO: Support running specific files
+ #self[:project_name] = args.shift
+ rescue OptionParser::InvalidOption => e
+ self[:invalid_argument] = e.message
+ end
+ end
+ end
+end
@@ -0,0 +1,8 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe UISpecRunner::Options do
+ it "should set the command to run_protocol" do
+ options = UISpecRunner::Options.new('-p UISpecIntegration')
+ options[:command].should == :run_protocol
+ end
+end
@@ -0,0 +1 @@
+--color
@@ -0,0 +1,9 @@
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+require 'UISpecRunner'
+require 'spec'
+require 'spec/autorun'
+
+Spec::Runner.configure do |config|
+
+end
@@ -0,0 +1,7 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe "UISpecRunner" do
+ it "fails" do
+ fail "hey buddy, you should probably rename this file and start specing for real"
+ end
+end

0 comments on commit a4bd7a4

Please sign in to comment.