blob: 5902edd5efad6962034a30a969834e377284ea3c [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with this
# work for additional information regarding copyright ownership. The ASF
# licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helpers'))
describe Project do
it 'should be findable' do
foo = define('foo')
project('foo').should be(foo)
end
it 'should not exist unless defined' do
lambda { project('foo') }.should raise_error(RuntimeError, /No such project/)
end
it 'should fail to be defined if its name is already used for a task' do
lambda { define('test') }.should raise_error(RuntimeError, /Invalid project name/i)
define 'valid' do
lambda { define('build') }.should raise_error(RuntimeError, /Invalid project name/i)
end
end
it 'should exist once defined' do
define 'foo'
lambda { project('foo') }.should_not raise_error
end
it 'should always return same project for same name' do
foo, bar = define('foo'), define('bar')
foo.should_not be(bar)
foo.should be(project('foo'))
bar.should be(project('bar'))
end
it 'should show up in projects list if defined' do
define('foo')
projects.map(&:name).should include('foo')
end
it 'should not show up in projects list unless defined' do
projects.map(&:name).should_not include('foo')
end
it 'should be findable from within a project' do
define('foo')
project('foo').project('foo').should be(project('foo'))
end
it 'should cease to exist when project list cleared' do
define 'foo'
projects.map(&:name).should include('foo')
Project.clear
projects.map(&:name).should be_empty
end
it 'should be defined only once' do
lambda { define 'foo' }.should_not raise_error
lambda { define 'foo' }.should raise_error
end
it 'should be definable in any order' do
Buildr.define('baz') { define('bar') { project('foo:bar') } }
Buildr.define('foo') { define('bar') }
lambda { project('foo') }.should_not raise_error
end
it 'should detect circular dependency' do
Buildr.define('baz') { define('bar') { project('foo:bar') } }
Buildr.define('foo') { define('bar') { project('baz:bar') } }
lambda { project('foo') }.should raise_error(RuntimeError, /Circular dependency/)
end
it 'should handle non-circular dependencies' do
Buildr.define "root" do
define "child" do
puts project('root')._('foo.resource')
end
end
lambda { project('root') }.should_not raise_error
end
end
describe Project, ' property' do
it 'should be set if passed as argument' do
define 'foo', 'version'=>'1.1'
project('foo').version.should eql('1.1')
end
it 'should be set if assigned in body' do
define('foo') { self.version = '1.2' }
project('foo').version.should eql('1.2')
end
it 'should take precedence when assigned in body' do
define('foo', 'version'=>'1.1') { self.version = '1.2' }
project('foo').version.should eql('1.2')
end
it 'should inherit from parent (for some properties)' do
define('foo', 'version'=>'1.2', :group=>'foobar') { define 'bar' }
project('foo:bar').version.should eql('1.2')
project('foo:bar').group.should eql('foobar')
end
it 'should have different value if set in sub-project' do
define 'foo', 'version'=>'1.2', :group=>'foobar' do
define 'bar', :version=>'1.3' do
self.group = 'barbaz'
end
end
project('foo:bar').version.should eql('1.3')
project('foo:bar').group.should eql('barbaz')
end
end
describe Project, ' block' do
it 'should execute once' do
define('foo') { self.name.should eql('foo') }
end
it 'should execute in describe of project' do
define('foo') { self.version = '1.3' }
project('foo').version.should eql('1.3')
end
it 'should execute by passing project' do
define('foo') { |project| project.version = '1.3' }
project('foo').version.should eql('1.3')
end
it 'should execute in namespace of project' do
define('foo') { define('bar') { Buildr.application.current_scope.should eql(['foo', 'bar']) } }
end
end
describe Project, '#base_dir' do
it 'should be pwd if not specified' do
define('foo').base_dir.should eql(Dir.pwd)
end
it 'should come from property, if specified' do
foo = define('foo', :base_dir=>'tmp')
foo.base_dir.should point_to_path('tmp')
end
it 'should be expanded path' do
foo = define('foo', :base_dir=>'tmp')
foo.base_dir.should eql(File.expand_path('tmp'))
end
it 'should be relative to parent project' do
define('foo') { define('bar') { define 'baz' } }
project('foo:bar:baz').base_dir.should point_to_path('bar/baz')
end
it 'should be settable only if not read' do
lambda { define('foo', :base_dir=>'tmp') }.should_not raise_error
lambda { define('bar', :base_dir=>'tmp') { self.base_dir = 'bar' } }.should raise_error(Exception, /Cannot set/)
end
end
describe Layout do
before :each do
@layout = Layout.new
end
it 'should expand empty to itself' do
@layout.expand.should eql('')
@layout.expand('').should eql('')
end
it 'should expand array of symbols' do
@layout.expand(:foo, :bar).should eql('foo/bar')
end
it 'should expand array of names' do
@layout.expand('foo', 'bar').should eql('foo/bar')
end
it 'should map symbol to path' do
@layout[:foo] = 'baz'
@layout.expand(:foo, :bar).should eql('baz/bar')
end
it 'should map symbols to path' do
@layout[:foo, :bar] = 'none'
@layout.expand(:foo, :bar).should eql('none')
end
it 'should map strings to path' do
@layout[:foo, "bar"] = 'none'
@layout.expand(:foo, :bar).should eql('none')
@layout.expand(:foo, 'bar').should eql('none')
end
it 'should ignore nil elements' do
@layout[:foo, :bar] = 'none'
@layout.expand(:foo, nil, :bar).should eql('none')
@layout.expand(nil, :foo).should eql('foo')
end
it 'should return nil if path not mapped' do
@layout[:foo].should be_nil
end
it 'should return path from symbol' do
@layout[:foo] = 'path'
@layout[:foo].should eql('path')
end
it 'should return path from symbol' do
@layout[:foo, :bar] = 'path'
@layout[:foo, :bar].should eql('path')
end
it 'should do eager mapping' do
@layout[:one] = 'none'
@layout[:one, :two] = '1..2'
@layout.expand(:one, :two, :three).should eql('1..2/three')
end
end
describe Project, '#layout' do
before :each do
@layout = Layout.new
end
it 'should exist by default' do
define('foo').layout.should respond_to(:expand)
end
it 'should be clone of default layout' do
define 'foo' do
layout.should_not be(Layout.default)
layout.expand(:test, :main).should eql(Layout.default.expand(:test, :main))
end
end
it 'should come from property, if specified' do
foo = define('foo', :layout=>@layout)
foo.layout.should eql(@layout)
end
it 'should inherit from parent project' do
define 'foo', :layout=>@layout do
layout[:foo] = 'foo'
define 'bar'
end
project('foo:bar').layout[:foo].should eql('foo')
end
it 'should clone when inheriting from parent project' do
define 'foo', :layout=>@layout do
layout[:foo] = 'foo'
define 'bar' do
layout[:foo] = 'bar'
end
end
project('foo').layout[:foo].should eql('foo')
project('foo:bar').layout[:foo].should eql('bar')
end
it 'should be settable only if not read' do
lambda { define('foo', :layout=>@layout) }.should_not raise_error
lambda { define('bar', :layout=>@layout) { self.layout = @layout.clone } }.should raise_error(Exception, /Cannot set/)
end
end
describe Project, '#path_to' do
it 'should return absolute paths as is' do
define('foo').path_to('/tmp').should eql(File.expand_path('/tmp'))
end
it 'should resolve empty path to project\'s base directory' do
define('foo').path_to.should eql(project('foo').base_dir)
end
it 'should resolve relative paths' do
define('foo').path_to('tmp').should eql(File.expand_path('tmp'))
end
it 'should accept multiple arguments' do
define('foo').path_to('foo', 'bar').should eql(File.expand_path('foo/bar'))
end
it 'should handle relative paths' do
define('foo').path_to('..', 'bar').should eql(File.expand_path('../bar'))
end
it 'should resolve symbols using layout' do
define('foo').layout[:foo] = 'bar'
project('foo').path_to(:foo).should eql(File.expand_path('bar'))
project('foo').path_to(:foo, 'tmp').should eql(File.expand_path('bar/tmp'))
end
it 'should resolve path for sub-project' do
define('foo') { define 'bar' }
project('foo:bar').path_to('foo').should eql(File.expand_path('foo', project('foo:bar').base_dir))
end
it 'should be idempotent for relative paths' do
define 'foo'
path = project('foo').path_to('bar')
project('foo').path_to(path).should eql(path)
end
end
describe Rake::Task, ' recursive' do
before do
define('foo') {
@order = []
def order
@order
end
recursive_task('doda') { project('foo').order << 'foo' }
define('bar') {
recursive_task('doda') { project('foo').order << 'foo:bar' }
define('baz') {
recursive_task('doda') { project('foo').order << 'foo:bar:baz' }
}
}
}
@order = project('foo').order
end
it 'should invoke same task in child project' do
task('foo:doda').invoke
@order.should include('foo:bar:baz')
@order.should include('foo:bar')
@order.should include('foo')
end
it 'should invoke in depth-first order' do
task('foo:doda').invoke
@order.should eql([ 'foo:bar:baz', 'foo:bar', 'foo' ])
end
it 'should not invoke task in parent project' do
task('foo:bar:baz:doda').invoke
@order.should eql([ 'foo:bar:baz' ])
end
end
describe 'Sub-project' do
it 'should point at parent project' do
define('foo') { define 'bar' }
project('foo:bar').parent.should be(project('foo'))
end
it 'should be defined only within parent project' do
lambda { define('foo:bar') }.should raise_error
end
it 'should have unique name' do
lambda do
define 'foo' do
define 'bar'
define 'bar'
end
end.should raise_error
end
it 'should be findable from root' do
define('foo') { define 'bar' }
projects.map(&:name).should include('foo:bar')
end
it 'should be findable from parent project' do
define('foo') { define 'bar' }
project('foo').projects.map(&:name).should include('foo:bar')
end
it 'should be findable during project definition' do
define 'foo' do
bar = define 'bar' do
baz = define 'baz'
project('baz').should eql(baz)
end
# Note: evaluating bar:baz first unearthed a bug that doesn't happen
# if we evaluate bar, then bar:baz.
project('bar:baz').should be(bar.project('baz'))
project('bar').should be(bar)
end
end
it 'should be findable only if exists' do
define('foo') { define 'bar' }
lambda { project('foo').project('baz') }.should raise_error(RuntimeError, /No such project/)
end
it 'should always execute its definition ' do
ordered = []
define 'foo' do
ordered << self.name
define('bar') { ordered << self.name }
define('baz') { ordered << self.name }
end
ordered.should eql(['foo', 'foo:bar', 'foo:baz'])
end
it 'should execute in order of dependency' do
ordered = []
define 'foo' do
ordered << self.name
define('bar') { project('foo:baz') ; ordered << self.name }
define('baz') { ordered << self.name }
end
ordered.should eql(['foo', 'foo:baz', 'foo:bar'])
end
it 'should warn of circular dependency' do
lambda do
define 'foo' do
define('bar') { project('foo:baz') }
define('baz') { project('foo:bar') }
end
end.should raise_error(RuntimeError, /Circular dependency/)
end
end
describe 'Top-level project' do
it 'should have no parent' do
define('foo')
project('foo').parent.should be_nil
end
end
describe Buildr, '#project' do
it 'should raise error if no such project' do
lambda { project('foo') }.should raise_error(RuntimeError, /No such project/)
end
it 'should return a project if exists' do
foo = define('foo')
project('foo').should be(foo)
end
it 'should define a project if a block is given' do
foo = project('foo') {}
project('foo').should be(foo)
end
it 'should define a project if properties and a block are given' do
foo = project('foo', :version => '1.2') {}
project('foo').should be(foo)
end
it 'should find a project by its full name' do
bar, baz = nil
define('foo') { bar = define('bar') { baz = define('baz') } }
project('foo:bar').should be(bar)
project('foo:bar:baz').should be(baz)
end
it 'should find a project from any context' do
bar, baz = nil
define('foo') { bar = define('bar') { baz = define('baz') } }
project('foo:bar').project('foo:bar:baz').should be(baz)
project('foo:bar:baz').project('foo:bar').should be(bar)
end
it 'should find a project from its parent or sibling project' do
define 'foo' do
define 'bar'
define 'baz'
end
project('foo').project('bar').should be(project('foo:bar'))
project('foo').project('baz').should be(project('foo:baz'))
project('foo:bar').project('baz').should be(project('foo:baz'))
end
it 'should find a project from its parent by proximity' do
define 'foo' do
define('bar') { define 'baz' }
define 'baz'
end
project('foo').project('baz').should be(project('foo:baz'))
project('foo:bar').project('baz').should be(project('foo:bar:baz'))
end
it 'should fail if called without a project name' do
lambda { project }.should raise_error(ArgumentError)
end
it 'should return self if called on a project without a name' do
define('foo') { project.should be(self) }
end
it 'should evaluate parent project before returning' do
# Note: gets around our define that also invokes the project.
Buildr.define('foo') { define('bar'); define('baz') }
project('foo:bar').should eql(projects[1])
end
end
describe Buildr, '#projects' do
it 'should only return defined projects' do
projects.should eql([])
define 'foo'
projects.should eql([project('foo')])
end
it 'should return all defined projects' do
define 'foo'
define('bar') { define 'baz' }
projects.should include(project('foo'))
projects.should include(project('bar'))
projects.should include(project('bar:baz'))
end
it 'should return only named projects' do
define 'foo' ; define 'bar' ; define 'baz'
projects('foo', 'bar').should include(project('foo'))
projects('foo', 'bar').should include(project('bar'))
projects('foo', 'bar').should_not include(project('baz'))
end
it 'should complain if named project does not exist' do
define 'foo'
projects('foo').should include(project('foo'))
lambda { projects('bar') }.should raise_error(RuntimeError, /No such project/)
end
it 'should find a project from its parent or sibling project' do
define 'foo' do
define 'bar'
define 'baz'
end
project('foo').projects('bar').should eql(projects('foo:bar'))
project('foo').projects('baz').should eql(projects('foo:baz'))
project('foo:bar').projects('baz').should eql(projects('foo:baz'))
end
it 'should fine a project from its parent by proximity' do
define 'foo' do
define('bar') { define 'baz' }
define 'baz'
end
project('foo').projects('baz').should eql(projects('foo:baz'))
project('foo:bar').projects('baz').should eql(projects('foo:bar:baz'))
end
it 'should evaluate all projects before returning' do
# Note: gets around our define that also invokes the project.
Buildr.define('foo') { define('bar'); define('baz') }
projects.should eql(projects('foo', 'foo:bar', 'foo:baz'))
end
end
describe Rake::Task, ' local directory' do
before do
@task = Project.local_task(task(('doda')))
end
it 'should execute project in local directory' do
define 'foo'
project('foo').tap { |project| task('doda') { |task| @task.from project.name } }
@task.should_receive(:from).with('foo')
@task.invoke
end
it 'should execute sub-project in local directory' do
@task.should_receive(:from).with('foo:bar')
define('foo') { define 'bar' }
project('foo:bar').tap { |project| task('doda') { |task| @task.from project.name } }
in_original_dir(project('foo:bar').base_dir) { @task.invoke }
end
it 'should do nothing if no project in local directory' do
@task.should_not_receive(:from)
define('foo') {
task('doda') { |task| @task.from project.name }
define 'bar'
}
in_original_dir('../not_foo') { @task.invoke }
end
it 'should find closest project that matches current directory' do
mkpath 'bar/src/main'
define('foo') { define 'bar' }
project('foo:bar').tap { |project| task('doda') { |task| @task.from project.name } }
@task.should_receive(:from).with('foo:bar')
in_original_dir('bar/src/main') { @task.invoke }
end
end
describe Project, '#task' do
it 'should create a regular task' do
define('foo') { task('bar') }
Buildr.application.lookup('foo:bar').should_not be_nil
end
it 'should return a task defined in the project' do
define('foo') { task('bar') }
project('foo').task('bar').should be_instance_of(Rake::Task)
end
it 'should not create task outside project definition' do
define 'foo'
lambda { project('foo').task('bar') }.should raise_error(RuntimeError, /no task foo:bar/)
end
it 'should include project name as prefix' do
define('foo') { task('bar') }
project('foo').task('bar').name.should eql('foo:bar')
end
it 'should ignore namespace if starting with colon' do
define 'foo' do
task(':bar').name.should == 'bar'
end
Rake::Task.task_defined?('bar').should be_true
end
it 'should accept single dependency' do
define('foo') { task('bar'=>'baz') }
project('foo').task('bar').prerequisites.should include('baz')
end
it 'should accept multiple dependencies' do
define('foo') { task('bar'=>['baz1', 'baz2']) }
project('foo').task('bar').prerequisites.should include('baz1')
project('foo').task('bar').prerequisites.should include('baz2')
end
it 'should execute task exactly once' do
define('foo') do
task 'baz'
task 'bar'=>'baz'
end
lambda { project('foo').task('bar').invoke }.should run_tasks(['foo:baz', 'foo:bar'])
end
it 'should create a file task' do
define('foo') { file('bar') }
Buildr.application.lookup(File.expand_path('bar')).should_not be_nil
end
it 'should create file task with absolute path' do
define('foo') { file('/tmp') }
Buildr.application.lookup(File.expand_path('/tmp')).should_not be_nil
end
it 'should create file task relative to project base directory' do
define('foo', :base_dir=>'tmp') { file('bar') }
Buildr.application.lookup(File.expand_path('tmp/bar')).should_not be_nil
end
it 'should accept single dependency' do
define('foo') { file('bar'=>'baz') }
project('foo').file('bar').prerequisites.should include('baz')
end
it 'should accept multiple dependencies' do
define('foo') { file('bar'=>['baz1', 'baz2']) }
project('foo').file('bar').prerequisites.should include('baz1')
project('foo').file('bar').prerequisites.should include('baz2')
end
it 'should accept hash arguments' do
define('foo') do
task 'bar'=>'bar_dep'
file 'baz'=>'baz_dep'
end
project('foo').task('bar').prerequisites.should include('bar_dep')
project('foo').file('baz').prerequisites.should include('baz_dep')
end
it 'should return a file task defined in the project' do
define('foo') { file('bar') }
project('foo').file('bar').should be_instance_of(Rake::FileTask)
end
it 'should create file task relative to project definition' do
define('foo') { define 'bar' }
project('foo:bar').file('baz').name.should point_to_path('bar/baz')
end
it 'should execute task exactly once' do
define('foo') do
task 'baz'
file 'bar'=>'baz'
end
lambda { project('foo').file('bar').invoke }.should run_tasks(['foo:baz', project('foo').path_to('bar')])
end
end
=begin
describe Buildr::Generate do
it 'should be able to create buildfile from directory structure' do
write 'src/main/java/Foo.java', ''
write 'one/two/src/main/java/Foo.java', ''
write 'one/three/src/main/java/Foo.java', ''
write 'four/src/main/java/Foo.java', ''
script = Buildr::Generate.from_directory(Dir.pwd)
instance_eval(script.join("\n"), "generated buildfile")
# projects should have been defined
root = Dir.pwd.pathmap('%n')
names = [root, "#{root}:one:two", "#{root}:one:three", "#{root}:four"]
# the top level project has the directory name.
names.each { |name| lambda { project(name) }.should_not raise_error }
end
end
=end