Class: GHUnit::Project

Inherits:
Object
  • Object
show all
Defined in:
lib/ghunit/project.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_path, target_name, test_target_name, logger = nil) ⇒ Project

Returns a new instance of Project.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/ghunit/project.rb', line 20

def initialize(project_path, target_name, test_target_name, logger=nil)
  @target_name = target_name
  @project_path = project_path
  @test_target_name = test_target_name
  @logger ||= begin
    logger = Logger.new(STDOUT)
    logger.formatter = proc do |severity, datetime, progname, msg|
      case severity
      when "ERROR"
        "#{msg}\n".red
      when "DEBUG"
        "#{msg}\n".green
      else
        "#{msg}\n"
      end
    end
    logger
  end
end

Instance Attribute Details

#loggerObject (readonly)

Returns the value of attribute logger.



16
17
18
# File 'lib/ghunit/project.rb', line 16

def logger
  @logger
end

#main_targetObject (readonly)

Returns the value of attribute main_target.



18
19
20
# File 'lib/ghunit/project.rb', line 18

def main_target
  @main_target
end

#projectObject (readonly)

Returns the value of attribute project.



18
19
20
# File 'lib/ghunit/project.rb', line 18

def project
  @project
end

#project_pathObject (readonly)

Returns the value of attribute project_path.



16
17
18
# File 'lib/ghunit/project.rb', line 16

def project_path
  @project_path
end

#target_nameObject (readonly)

Returns the value of attribute target_name.



16
17
18
# File 'lib/ghunit/project.rb', line 16

def target_name
  @target_name
end

#test_target_nameObject (readonly)

Returns the value of attribute test_target_name.



16
17
18
# File 'lib/ghunit/project.rb', line 16

def test_target_name
  @test_target_name
end

Class Method Details

.open(project_path, target_name, test_target_name, logger = nil) ⇒ Object

Initialize and open a project.



62
63
64
65
66
67
68
69
# File 'lib/ghunit/project.rb', line 62

def open(project_path, target_name, test_target_name, logger=nil)
  project = GHUnit::Project.new(project_path, target_name, test_target_name, logger)
  if project.open
    project
  else
    nil
  end
end

.open_from_opts(opts) ⇒ Object

Open from slop options. This is only meant to be called from the ghunit bin executable, it outputs to STDOUT and calls exit.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/ghunit/project.rb', line 75

def open_from_opts(opts)
  target_name = opts[:name]
  project_path = opts[:path] || "#{target_name}.xcodeproj"
  test_target_name = opts[:test_target] || "Tests"

  if !target_name
    puts " "
    puts "Need to specify a project name.".red
    puts " "
    puts opts.to_s
    puts " "
    exit 1
  end

  self.open(project_path, target_name, test_target_name)
end

Instance Method Details

#add_test_file(path) ⇒ Object

Add a file to the test target



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/ghunit/project.rb', line 221

def add_test_file(path)
  test_target = find_test_target
  if !test_target
    logger.error "No test target to add to"
    return false
  end

  tests_group = project.groups.select { |g| g.name == test_target_name }.first
  tests_group ||= project.new_group(test_target_name)

  test_file = tests_group.find_file_by_path(path)
  if !test_file
    test_file = tests_group.new_file(path)
  end
  test_target.add_file_references([test_file])
  true
end

#check_podObject

Check the Podfile or just display some Podfile help



268
269
270
271
272
273
274
275
276
277
278
# File 'lib/ghunit/project.rb', line 268

def check_pod
  logger.info <<-EOS

Add the following to your Podfile and run pod install.

#{template("Podfile")}

Make sure to open the .xcworkspace.

EOS
end

#create_test(name, template_type = nil) ⇒ Object

Create test file and add it to the test target.

Parameters:

  • name

    Name of test class and file name

  • template_type (defaults to: nil)

    nil or “kiwi”



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/ghunit/project.rb', line 244

def create_test(name, template_type=nil)
  template_type ||= :ghunit

  template_name = case template_type.to_sym
  when :kiwi
    "TestKiwi.m.erb"
  when :ghunit
    "Test.m.erb"
  end

  if name.end_with?(".m")
    name = name[0...-2]
  end
  template_vars = {test_class_name: name}
  path = create_test_file("#{name}.m", template(template_name, template_vars))
  path
end

#create_test_file(file_name, content, force = false) ⇒ Object

Create a file with content and add to the test target



213
214
215
216
217
# File 'lib/ghunit/project.rb', line 213

def create_test_file(file_name, content, force=false)
  path = write_test_file(file_name, content, force)
  add_test_file(path)
  path
end

#create_test_targetObject

Create the test target and setup everything



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/ghunit/project.rb', line 99

def create_test_target
  Dir.chdir(File.dirname(project_path))
  FileUtils.mkdir_p(test_target_name)

  # Write the Tests-Info.plist
  test_info = {
    "CFBundleDisplayName" => "${PRODUCT_NAME}",
    "CFBundleExecutable" => "${EXECUTABLE_NAME}",
    "CFBundleIdentifier" =>  "tests.${PRODUCT_NAME:rfc1034identifier}",
    "CFBundleInfoDictionaryVersion" => "6.0",
    "CFBundleName" => "${PRODUCT_NAME}",
    "CFBundlePackageType" => "APPL",
    "CFBundleShortVersionString" => "1.0",
    "CFBundleVersion" => "1.0",
    "LSRequiresIPhoneOS" => true,
    "UISupportedInterfaceOrientations" => ["UIInterfaceOrientationPortrait"]
  }
  test_info_path = File.join(test_target_name, "#{test_target_name}-Info.plist")
  if !File.exists?(test_info_path)
    logger.debug "Creating: #{test_info_path}"
    Xcodeproj.write_plist(test_info, test_info_path)
  else
    logger.debug "#{test_info_path} already exists, skipping..."
  end

  test_target = find_test_target
  if !test_target

    # Create the test target
    logger.debug "Creating target: #{test_target_name}"
    test_target = project.new_target(:application, test_target_name, :ios, "7.0")
    test_target.add_dependency(main_target)

    create_test_file("main.m", template("main.m"), true)
    create_test("MyTest")

    #
    # No longer doing this (using same resource build phase as main target).
    # It causes crashes in latest xCode.
    #
    # Use same resources build phase as main target
    # Have to compare with class name because of funky const loading in xcodeproj gem
    # resources_build_phase = main_target.build_phases.select { |p|
    #   p.class == Xcodeproj::Project::Object::PBXResourcesBuildPhase }.first
    # test_target.build_phases << resources_build_phase if resources_build_phase

    # Add resources build phase if one doesn't exist
    resources_build_phase = test_target.build_phases.select { |p|
      p.class == Xcodeproj::Project::Object::PBXResourcesBuildPhase }.first

    test_target.build_phases << project.new(Xcodeproj::Project::Object::PBXResourcesBuildPhase) unless resources_build_phase
  else
    logger.debug "Test target already exists, skipping..."
  end

  # Get main target prefix header
  debug_settings = main_target.build_settings("Debug")
  prefix_header = debug_settings["GCC_PREFIX_HEADER"] if debug_settings

  # Clear default OTHER_LDFLAGS (otherwise CocoaPods gives a warning)
  test_target.build_configurations.each do |c|
    c.build_settings.delete("OTHER_LDFLAGS")
    c.build_settings["INFOPLIST_FILE"] = test_info_path
    c.build_settings["GCC_PREFIX_HEADER"] = prefix_header if prefix_header
  end

  # Write any test support files
  write_test_file("RunTests.sh", template("RunTests.sh"), true)

  # Create test scheme if it doesn't exist
  logger.debug "Checking for Test scheme..."
  schemes = Xcodeproj::Project.schemes(project_path)
  test_scheme = schemes.select { |s| s == test_target_name }.first
  if !test_scheme
    logger.debug "Test scheme not found, creating..."
    scheme = Xcodeproj::XCScheme.new
    scheme.set_launch_target(test_target)
    scheme.save_as(project_path, test_target_name)
  else
    logger.debug "Test scheme already exists, skipping..."
  end

  logger.debug "Saving project..."
  project.save

  check_pod
end

#find_test_targetObject



93
94
95
# File 'lib/ghunit/project.rb', line 93

def find_test_target
  project.targets.select { |t| t.name == test_target_name }.first
end

#install_run_tests_scriptObject



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/ghunit/project.rb', line 313

def install_run_tests_script
  run_script_name = "Run Tests (CLI)"
  # Find run script build phase and install RunTests.sh
  test_target = find_test_target
  run_script_phase = test_target.build_phases.select { |p|
    p.class == Xcodeproj::Project::Object::PBXShellScriptBuildPhase &&
    p.name == run_script_name }.first
  if !run_script_phase
    logger.debug "Installing run tests script..."
    run_script_phase = project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
    run_script_phase.name = run_script_name
    run_script_phase.shell_script = "sh Tests/RunTests.sh"
    test_target.build_phases << run_script_phase
  end
  project.save
end

#openObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ghunit/project.rb', line 40

def open
  if !File.exists?(project_path)
    logger.error "Can't find project path at #{project_path}"
    return false
  end

  @project = Xcodeproj::Project.open(project_path)

  # Find the main target for the test dependency
  @main_target = project.targets.select { |t| t.name == target_name }.first
  if !@main_target
    logger.error "No target with name #{target_name}"
    return false
  end

  true
end

#saveObject



262
263
264
# File 'lib/ghunit/project.rb', line 262

def save
  @project.save
end

#sync_test_target_membershipObject



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/ghunit/project.rb', line 280

def sync_test_target_membership
  test_target = find_test_target
  if !test_target
    logger.error "No test target to add to"
    return false
  end

  tests_group = project.groups.select { |g| g.name == test_target_name }.first
  if !tests_group
    logger.error "No test group to add to"
    return false
  end

  sources_phase = main_target.build_phases.select { |p|
    p.class == Xcodeproj::Project::Object::PBXSourcesBuildPhase }.first

  if !sources_phase
    logger.error "No main target source phase found"
    return false
  end

  logger.debug "Adding to test target: "
  sources_phase.files_references.each do |file_ref|
    next if file_ref.path == "main.m"
    test_file = tests_group.find_file_by_path(file_ref.path)
    if !test_file
      logger.debug "  #{file_ref.path}"
      test_target.add_file_references([file_ref])
    end
  end
  project.save
end

#template(name, template_vars = nil) ⇒ Object



187
188
189
190
191
192
193
194
195
196
# File 'lib/ghunit/project.rb', line 187

def template(name, template_vars=nil)
  template_path = File.join(File.dirname(__FILE__), "templates", name)
  content = File.read(template_path)

  if template_path.end_with?(".erb")
    et = ErbalT.new(template_vars)
    content = et.render(content)
  end
  content
end

#write_test_file(file_name, content, force = false) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/ghunit/project.rb', line 198

def write_test_file(file_name, content, force=false)
  # Create file in tests dir
  path = File.join(test_target_name, file_name)

  if !force && File.exists?(path)
    logger.info "Test file already exists, skipping"
  end

  logger.debug "Creating: #{path}"
  File.open(path, "w") { |f| f.write(content) }
  path
end