# 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'))
JAVA_CONTAINER = Buildr::Eclipse::Java::CONTAINER
SCALA_CONTAINER = Buildr::Eclipse::Scala::CONTAINER
PLUGIN_CONTAINER = Buildr::Eclipse::Plugin::CONTAINER
JAVA_NATURE = Buildr::Eclipse::Java::NATURE
SCALA_NATURE = Buildr::Eclipse::Scala::NATURE
PLUGIN_NATURE = Buildr::Eclipse::Plugin::NATURE
JAVA_BUILDER = Buildr::Eclipse::Java::BUILDER
SCALA_BUILDER = Buildr::Eclipse::Scala::BUILDER
PLUGIN_BUILDERS = Buildr::Eclipse::Plugin::BUILDERS
module EclipseHelper
def classpath_xml_elements
task('eclipse').invoke
File.open('.classpath') { |f| REXML::Document.new(f).root.elements }
end
def classpath_sources(attribute='path')
classpath_xml_elements.collect("classpathentry[@kind='src']") { |n| n.attributes[attribute] }
end
#
def classpath_specific_output(path)
specific_output = classpath_xml_elements.collect("classpathentry[@path='#{path}']") { |n| n.attributes['output'] }
raise "expected: one output attribute for path '#{path}, got: #{specific_output.inspect}" if specific_output.length > 1
specific_output[0]
end
#
def classpath_default_output
default_output = classpath_xml_elements.collect("classpathentry[@kind='output']") { |n| n.attributes['path'] }
raise "expected: one path attribute for kind='output', got: #{default_output.inspect}" if default_output.length > 1
default_output[0]
end
#
def sourcepath_for_path(path)
classpath_xml_elements.collect("classpathentry[@kind='var',@path='#{path}']") do |n|
n.attributes['sourcepath'] || 'no source artifact'
end
end
#
def javadocpath_for_path(path)
classpath_xml_elements.collect("classpathentry[@kind='var',@path='#{path}']") do |n|
n.attributes['javadocpath'] || 'no javadoc artifact'
end
end
def project_xml_elements
task('eclipse').invoke
File.open('.project') { |f| REXML::Document.new(f).root.elements }
end
def project_natures
project_xml_elements.collect("natures/nature") { |n| n.text }
end
def build_commands
project_xml_elements.collect("buildSpec/buildCommand/name") { |n| n.text }
end
def classpath_containers(attribute='path')
classpath_xml_elements.collect("classpathentry[@kind='con']") { |n| n.attributes[attribute] }
end
end
describe Buildr::Eclipse do
include EclipseHelper
describe "eclipse's .project file" do
describe 'default project' do
before do
write 'buildfile'
write 'src/main/nono/Main.nono'
end
it 'should not have natures' do
define('foo')
project_natures.should be_empty
end
it 'should not have build commands' do
define('foo')
build_commands.should be_empty
end
it 'should generate a .project file' do
define('foo')
task('eclipse').invoke
File.open('.project') do |f|
REXML::Document.new(f).root.
elements.collect("name") { |e| e.text }.should == ['foo']
end
end
it 'should use eclipse project name if specified' do
define('foo') { eclipse.name = 'bar' }
task('eclipse').invoke
File.open('.project') do |f|
REXML::Document.new(f).root.
elements.collect("name") { |e| e.text }.should == ['bar']
end
end
it 'should not generate a .classpath file' do
define('foo')
task('eclipse').invoke
File.exists?('.classpath').should be_false
end
end
describe 'parent project' do
before do
write 'buildfile'
mkpath 'bar'
end
it 'should not generate a .project for the parent project' do
define('foo') do
define('bar')
end
task('eclipse').invoke
File.exists?('.project').should be_false
File.exists?(File.join('bar','.project')).should be_true
end
end
describe 'java project' do
before do
write 'buildfile'
write 'src/main/java/Main.java'
end
it 'should have Java nature' do
define('foo')
project_natures.should include(JAVA_NATURE)
end
it 'should have Java build command' do
define('foo')
build_commands.should include(JAVA_BUILDER)
end
end
describe 'nested java project' do
it 'should have name corresponding to its project definition' do
mkdir 'foo'
define('myproject') {
project.version = '1.0'
define('foo') { compile.using(:javac); package :jar }
}
task('eclipse').invoke
File.open(File.join('foo', '.project')) do |f|
REXML::Document.new(f).root.
elements.collect("name") { |e| e.text }.should == ['myproject-foo']
end
end
it 'should use eclipse name for child project if set' do
mkdir 'foo'
define('myproject') {
project.version = '1.0'
define('foo') { eclipse.name = 'bar'; compile.using(:javac); package :jar }
}
task('eclipse').invoke
File.open(File.join('foo', '.project')) do |f|
REXML::Document.new(f).root.
elements.collect("name") { |e| e.text }.should == ['bar']
end
end
it 'should use short name for child project if eclipse.options.short_names = true' do
mkdir 'foo'
define('myproject') {
project.version = '1.0'
eclipse.options.short_names = true
define('foo') { compile.using(:javac); package :jar }
}
task('eclipse').invoke
File.open(File.join('foo', '.project')) do |f|
REXML::Document.new(f).root.
elements.collect("name") { |e| e.text }.should == ['foo']
end
end
end
describe 'scala project' do
before do
define 'foo' do
eclipse.natures :scala
end
end
it 'should have Scala nature before Java nature' do
project_natures.should include(SCALA_NATURE)
project_natures.should include(JAVA_NATURE)
project_natures.index(SCALA_NATURE).should < project_natures.index(JAVA_NATURE)
end
it 'should have Scala build command and no Java build command' do
build_commands.should include(SCALA_BUILDER)
build_commands.should_not include(JAVA_BUILDER)
end
end
describe 'standard scala project' do
before do
write 'buildfile'
write 'src/main/scala/Main.scala'
define 'foo'
end
it 'should have Scala nature before Java nature' do
project_natures.should include(SCALA_NATURE)
project_natures.should include(JAVA_NATURE)
project_natures.index(SCALA_NATURE).should < project_natures.index(JAVA_NATURE)
end
it 'should have Scala build command and no Java build command' do
build_commands.should include(SCALA_BUILDER)
build_commands.should_not include(JAVA_BUILDER)
end
end
describe 'non-standard scala project' do
before do
write 'buildfile'
write 'src/main/foo/Main.scala'
define 'foo' do
eclipse.natures = :scala
end
end
it 'should have Scala nature before Java nature' do
project_natures.should include(SCALA_NATURE)
project_natures.should include(JAVA_NATURE)
project_natures.index(SCALA_NATURE).should < project_natures.index(JAVA_NATURE)
end
it 'should have Scala build command and no Java build command' do
build_commands.should include(SCALA_BUILDER)
build_commands.should_not include(JAVA_BUILDER)
end
end
describe 'Plugin project' do
before do
write 'buildfile'
write 'src/main/java/Activator.java'
write 'plugin.xml'
end
it 'should have plugin nature before Java nature' do
define('foo')
project_natures.should include(PLUGIN_NATURE)
project_natures.should include(JAVA_NATURE)
project_natures.index(PLUGIN_NATURE).should < project_natures.index(JAVA_NATURE)
end
it 'should have plugin build commands and the Java build command' do
define('foo')
build_commands.should include(PLUGIN_BUILDERS[0])
build_commands.should include(PLUGIN_BUILDERS[1])
build_commands.should include(JAVA_BUILDER)
end
end
describe 'Plugin project' do
before do
write 'buildfile'
write 'src/main/java/Activator.java'
write 'plugin.xml'
end
it 'should have plugin nature before Java nature' do
define('foo')
project_natures.should include(PLUGIN_NATURE)
project_natures.should include(JAVA_NATURE)
project_natures.index(PLUGIN_NATURE).should < project_natures.index(JAVA_NATURE)
end
it 'should have plugin build commands and the Java build command' do
define('foo')
build_commands.should include(PLUGIN_BUILDERS[0])
build_commands.should include(PLUGIN_BUILDERS[1])
build_commands.should include(JAVA_BUILDER)
end
end
describe 'Plugin project with META-INF/MANIFEST.MF' do
before do
write 'buildfile'
write 'src/main/java/Activator.java'
end
it 'should have plugin nature by default if MANIFEST.MF contains "Bundle-SymbolicName:"' do
write 'META-INF/MANIFEST.MF', <<-MANIFEST
Manifest-Version: 1.0
Name: example/
Specification-Title: "Examples"
Specification-Version: "1.0"
Specification-Vendor: "Acme Corp.".
Implementation-Title: "example"
Implementation-Version: "build57"
Implementation-Vendor: "Acme Corp."
Bundle-SymbolicName: acme.plugin.example
MANIFEST
define('foo')
project_natures.should include(PLUGIN_NATURE)
end
it 'should not have plugin nature if MANIFEST.MF exists but doesn\'t contain "Bundle-SymbolicName:"' do
write 'META-INF/MANIFEST.MF', <<-MANIFEST
Manifest-Version: 1.0
Name: example/
Specification-Title: "Examples"
Specification-Version: "1.0"
Specification-Vendor: "Acme Corp.".
Implementation-Title: "example"
Implementation-Version: "build57"
Implementation-Vendor: "Acme Corp."
MANIFEST
define('foo')
project_natures.should_not include(PLUGIN_NATURE)
end
end
end
describe "eclipse's .classpath file" do
describe 'scala project' do
before do
write 'buildfile'
write 'src/main/scala/Main.scala'
end
it 'should have SCALA_CONTAINER before JAVA_CONTAINER' do
define('foo')
classpath_containers.should include(SCALA_CONTAINER)
classpath_containers.should include(JAVA_CONTAINER)
classpath_containers.index(SCALA_CONTAINER).should < classpath_containers.index(JAVA_CONTAINER)
end
end
describe 'source folders' do
before do
write 'buildfile'
write 'src/main/java/Main.java'
write 'src/test/java/Test.java'
end
shared_examples_for 'source' do
it 'should ignore CVS and SVN files' do
define('foo')
classpath_sources('excluding').each do |excluding_attribute|
excluding = excluding_attribute.split('|')
excluding.should include('**/.svn/')
excluding.should include('**/CVS/')
end
end
end
describe 'main code' do
it_should_behave_like 'source'
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/main/java')
end
it 'should accept to come from a user-defined directory' do
define('foo') { compile path_to('src/java') }
classpath_sources.should include('src/java')
end
it 'should accept a file task as a main source folder' do
define('foo') { compile apt }
classpath_sources.should include('target/generated/apt')
end
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/main/java').should be(nil)
classpath_default_output.should == 'target/classes'
end
end
describe 'test code' do
it_should_behave_like 'source'
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/test/java')
end
it 'should accept to come from a user-defined directory' do
define('foo') { test.compile path_to('src/test') }
classpath_sources.should include('src/test')
end
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/test/java').should == 'target/test/classes'
end
it 'should accept to be the only code in the project' do
rm 'src/main/java/Main.java'
define('foo')
classpath_sources.should include('src/test/java')
end
end
describe 'main resources' do
it_should_behave_like 'source'
before do
write 'src/main/resources/config.xml'
end
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/main/resources')
end
it 'should share a classpath entry if it comes from a directory with code' do
write 'src/main/java/config.properties'
define('foo') { resources.from('src/main/java').exclude('**/*.java') }
classpath_sources.select { |path| path == 'src/main/java'}.length.should == 1
end
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/main/resources').should == 'target/resources'
end
end
describe 'test resources' do
it_should_behave_like 'source'
before do
write 'src/test/resources/config-test.xml'
end
it 'should accept to come from the default directory' do
define('foo')
classpath_sources.should include('src/test/resources')
end
it 'should share a classpath entry if it comes from a directory with code' do
write 'src/test/java/config-test.properties'
define('foo') { test.resources.from('src/test/java').exclude('**/*.java') }
classpath_sources.select { |path| path == 'src/test/java'}.length.should == 1
end
it 'should go to the default target directory' do
define('foo')
classpath_specific_output('src/test/resources').should == 'target/test/resources'
end
end
end
describe 'project depending on another project' do
it 'should have the underlying project in its classpath' do
mkdir 'foo'
mkdir 'bar'
define('myproject') {
project.version = '1.0'
define('foo') { package :jar }
define('bar') { compile.using(:javac).with project('foo'); }
}
task('eclipse').invoke
File.open(File.join('bar', '.classpath')) do |f|
REXML::Document.new(f).root.
elements.collect("classpathentry[@kind='src']") { |n| n.attributes['path'] }.should include('/myproject-foo')
end
end
it 'should use eclipse name in its classpath if set' do
mkdir 'foo'
mkdir 'bar'
define('myproject') {
project.version = '1.0'
define('foo') { eclipse.name = 'eclipsefoo'; package :jar }
define('bar') { eclipse.name = 'eclipsebar'; compile.using(:javac).with project('foo'); }
}
task('eclipse').invoke
File.open(File.join('bar', '.classpath')) do |f|
REXML::Document.new(f).root.
elements.collect("classpathentry[@kind='src']") { |n| n.attributes['path'] }.should include('/eclipsefoo')
end
end
end
end
describe 'local dependency' do
before do
write 'lib/some-local.jar'
define('foo') { compile.using(:javac).with(_('lib/some-local.jar')) }
end
it 'should have a lib artifact reference in the .classpath file' do
classpath_xml_elements.collect("classpathentry[@kind='lib']") { |n| n.attributes['path'] }.
should include('lib/some-local.jar')
end
end
describe 'project .classpath' do
before do
mkdir_p '../libs'
write '../libs/some-local.jar'
define('foo') do
eclipse.classpath_variables :LIBS => '../libs', :LIBS2 => '../libs2'
compile.using(:javac).with(_('../libs/some-local.jar'))
end
end
after do
rm_rf '../libs'
end
it 'supports generating library paths with classpath variables' do
classpath_xml_elements.collect("classpathentry[@kind='var']") { |n| n.attributes['path'] }.
should include('LIBS/some-local.jar')
end
end
describe 'generated .classes' do
before do
write 'lib/some.class'
define('foo') { compile.using(:javac).with(_('lib')) }
end
it 'should have src reference in the .classpath file' do
classpath_xml_elements.collect("classpathentry[@kind='src']") { |n| n.attributes['path'] }.
should include('lib')
end
end
describe 'maven2 artifact dependency' do
before do
define('foo') { compile.using(:javac).with('com.example:library:jar:2.0') }
artifact('com.example:library:jar:2.0') { |task| write task.name }
task('eclipse').invoke
end
it 'should have a reference in the .classpath file relative to the local M2 repo' do
classpath_xml_elements.collect("classpathentry[@kind='var']") { |n| n.attributes['path'] }.
should include('M2_REPO/com/example/library/2.0/library-2.0.jar')
end
it 'should be downloaded' do
file(artifact('com.example:library:jar:2.0').name).should exist
end
it 'should have a source artifact reference in the .classpath file' do
sourcepath_for_path('M2_REPO/com/example/library/2.0/library-2.0.jar').
should == ['M2_REPO/com/example/library/2.0/library-2.0-sources.jar']
end
it 'should have a javadoc artifact reference in the .classpath file' do
javadocpath_for_path('M2_REPO/com/example/library/2.0/library-2.0.jar').
should == ['M2_REPO/com/example/library/2.0/library-2.0-javadoc.jar']
end
end
describe 'maven2 repository variable' do
it 'should be configurable' do
define('foo') do
eclipse.options.m2_repo_var = 'PROJ_REPO'
compile.using(:javac).with('com.example:library:jar:2.0')
end
artifact('com.example:library:jar:2.0') { |task| write task.name }
task('eclipse').invoke
classpath_xml_elements.collect("classpathentry[@kind='var']") { |n| n.attributes['path'] }.
should include('PROJ_REPO/com/example/library/2.0/library-2.0.jar')
end
it 'should pick the parent value by default' do
define('foo') do
eclipse.options.m2_repo_var = 'FOO_REPO'
define('bar')
define('bar2') do
eclipse.options.m2_repo_var = 'BAR2_REPO'
end
end
project('foo:bar').eclipse.options.m2_repo_var.should eql('FOO_REPO')
project('foo:bar2').eclipse.options.m2_repo_var.should eql('BAR2_REPO')
end
end
describe 'natures variable' do
it 'should be configurable' do
define('foo') do
eclipse.natures = 'dummyNature'
compile.using(:javac).with('com.example:library:jar:2.0')
end
artifact('com.example:library:jar:2.0') { |task| write task.name }
project_natures.should include('dummyNature')
end
it 'should pick the parent value by default' do
define('foo') do
eclipse.natures = 'foo_nature'
define('bar')
define('bar2') do
eclipse.natures = 'bar2_nature'
end
end
project('foo:bar').eclipse.natures.should include('foo_nature')
project('foo:bar2').eclipse.natures.should include('bar2_nature')
end
it 'should handle arrays correctly' do
define('foo') do
eclipse.natures ['foo_nature', 'bar_nature']
end
project('foo').eclipse.natures.should == ['foo_nature', 'bar_nature']
end
end
describe 'builders variable' do
it 'should be configurable' do
define('foo') do
eclipse.builders 'dummyBuilder'
compile.using(:javac).with('com.example:library:jar:2.0')
end
artifact('com.example:library:jar:2.0') { |task| write task.name }
build_commands.should include('dummyBuilder')
end
it 'should pick the parent value by default' do
define('foo') do
eclipse.builders = 'foo_builder'
define('bar')
define('bar2') do
eclipse.builders = 'bar2_builder'
end
end
project('foo:bar').eclipse.builders.should include('foo_builder')
project('foo:bar2').eclipse.builders.should include('bar2_builder')
end
it 'should handle arrays correctly' do
define('foo') do
eclipse.builders ['foo_builder', 'bar_builder']
end
project('foo').eclipse.builders.should == ['foo_builder', 'bar_builder']
end
end
describe 'classpath_containers variable' do
it 'should be configurable' do
define('foo') do
eclipse.classpath_containers = 'myOlGoodContainer'
compile.using(:javac).with('com.example:library:jar:2.0')
end
artifact('com.example:library:jar:2.0') { |task| write task.name }
classpath_containers.should include('myOlGoodContainer')
end
it 'should pick the parent value by default' do
define('foo') do
eclipse.classpath_containers = 'foo_classpath_containers'
define('bar')
define('bar2') do
eclipse.classpath_containers = 'bar2_classpath_containers'
end
end
project('foo:bar').eclipse.classpath_containers.should include('foo_classpath_containers')
project('foo:bar2').eclipse.classpath_containers.should include('bar2_classpath_containers')
end
it 'should handle arrays correctly' do
define('foo') do
eclipse.classpath_containers ['foo_cc', 'bar_cc']
end
project('foo').eclipse.classpath_containers.should == ['foo_cc', 'bar_cc']
end
end
describe 'exclude_libs' do
it 'should support artifacts' do
define('foo') do
compile.using(:javac).with('com.example:library:jar:2.0')
eclipse.exclude_libs += [ artifact('com.example:library:jar:2.0') ]
end
artifact('com.example:library:jar:2.0') { |task| write task.name }
task('eclipse').invoke
classpath_xml_elements.collect("classpathentry[@kind='var']") { |n| n.attributes['path'] }.
should_not include('M2_REPO/com/example/library/2.0/library-2.0.jar')
end
it 'should support string paths' do
define('foo') do
compile.using(:javac).with _('path/to/library.jar')
eclipse.exclude_libs += [ _('path/to/library.jar') ]
end
write project('foo').path_to('path/to/library.jar')
task('eclipse').invoke
classpath_xml_elements.collect("classpathentry[@kind='lib']") { |n| n.attributes['path'] }.
should_not include('path/to/library.jar')
end
end
end