| # 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 |