Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to install test dependencies and run tests to Pkg #6191

Merged
merged 8 commits into from
Mar 21, 2014
6 changes: 5 additions & 1 deletion base/pkg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Pkg

export Git, Dir, GitHub, Types, Reqs, Cache, Read, Query, Resolve, Write, Generate, Entry
export dir, init, rm, add, available, installed, status, clone, checkout,
release, fix, update, resolve, register, tag, publish, generate
release, fix, update, resolve, register, tag, publish, generate, test

const DEFAULT_META = "git://github.com/JuliaLang/METADATA.jl"
const META_BRANCH = "metadata-v2"
Expand Down Expand Up @@ -62,6 +62,10 @@ build(pkgs::String...) = cd(Entry.build,[pkgs...])
generate(pkg::String, license::String; force::Bool=false) =
cd(Generate.package,pkg,license,force=force)


test() = cd(Entry.test)
test(pkgs::String...) = cd(Entry.test,String[pkgs...])

@deprecate release free
@deprecate fixup build
@deprecate fix pin
Expand Down
42 changes: 42 additions & 0 deletions base/pkg/entry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -663,4 +663,46 @@ function updatehook(pkgs::Vector)
""")
end

@windows_only const JULIA = joinpath(JULIA_HOME, ENV["JULIA_EXE"])
@unix_only const JULIA = joinpath(JULIA_HOME, "julia-readline")

function test!(pkg::String, errs::Vector{String}, notests::Vector{String})
const tests_require = Reqs.parse("$pkg/REQUIRE",true)
if (!isempty(tests_require))
info("Computing test dependencies for $pkg...")
resolve(tests_require)
end
const path = abspath(pkg,"run_tests.jl")
if isfile(path)
info("Testing $pkg")
cd(dirname(path)) do
try
run(`$JULIA $path`)
info("$pkg tests passed")
catch err
warnbanner(err, label="[ ERROR: $pkg ]")
push!(errs,pkg)
end
end
else
push!(notests,pkg)
end
end

function test(pkgs::Vector{String})
errs = String[]
notests = String[]
for pkg in pkgs
test!(pkg,errs,notests)
end
if !isempty(errs) || !isempty(notests)
messages = String[]
isempty(errs) || push!(messages, "$(join(errs,", "," and ")) had test errors")
isempty(notests) || push!(messages, "$(join(notests,", "," and ")) did not provide a run_test.jl file")
error(join(messages, "and"))
end
end

test() = test(sort!(String[keys(installed())...]))

end # module
16 changes: 12 additions & 4 deletions base/pkg/reqs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,27 @@ immutable Requirement <: Line
package::String
versions::VersionSet
system::Vector{String}
test::Bool

function Requirement(content::String)
test = false
fields = split(replace(content, r"#.*$", ""))
system = String[]
while !isempty(fields) && fields[1][1] == '@'
push!(system,shift!(fields)[2:end])
sys = shift!(fields)[2:end]
if sys=="test"
test = true
else
push!(system, sys)
end
end
isempty(fields) && error("invalid requires entry: $content")
package = shift!(fields)
all(field->ismatch(Base.VERSION_REGEX, field), fields) ||
error("invalid requires entry for $package: $content")
versions = [ convert(VersionNumber, field) for field in fields ]
issorted(versions) || error("invalid requires entry for $package: $content")
new(content, package, VersionSet(versions), system)
new(content, package, VersionSet(versions), system, test)
end
function Requirement(package::String, versions::VersionSet, system::Vector{String}=String[])
content = ""
Expand Down Expand Up @@ -72,7 +79,7 @@ function write(io::IO, reqs::Requires)
end
write(file::String, r::Union(Vector{Line},Requires)) = open(io->write(io,r), file, "w")

function parse(lines::Vector{Line})
function parse(lines::Vector{Line}, test::Bool=false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would do better as a keyword argument. It is not obvious what parse(lines, true) means, but parse(lines, test=true) makes it obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and will change this

reqs = Requires()
for line in lines
if isa(line,Requirement)
Expand All @@ -88,13 +95,14 @@ function parse(lines::Vector{Line})
@linux_only applies &= !("!linux" in line.system)
applies || continue
end
(test==line.test) || continue
reqs[line.package] = haskey(reqs, line.package) ?
intersect(reqs[line.package], line.versions) : line.versions
end
end
return reqs
end
parse(x) = parse(read(x))
parse(x, test::Bool=false) = parse(read(x),test)

# add & rm – edit the content a requires file

Expand Down
72 changes: 64 additions & 8 deletions test/pkg.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,71 @@
ENV["JULIA_PKGDIR"] = string("tmp.",randstring())
@test !isdir(Pkg.dir())
try # ensure directory removal
Pkg.init()
@test isdir(Pkg.dir())
Pkg.resolve()
function temp_pkg_dir(fn::Function)
# Used in tests below to setup and teardown a sandboxed package directory
const tmpdir = ENV["JULIA_PKGDIR"] = string("tmp.",randstring())
@test !isdir(Pkg.dir())
try
Pkg.init()
@test isdir(Pkg.dir())
Pkg.resolve()

fn()
finally
run(`rm -rf $tmpdir`)
end
end

# Test adding a removing a package
temp_pkg_dir() do
@test isempty(Pkg.installed())
Pkg.add("Example")
@test [keys(Pkg.installed())...] == ["Example"]
Pkg.rm("Example")
@test isempty(Pkg.installed())
finally
run(`rm -rf $(Pkg.dir())`)
end

# testing a package with @test dependencies causes them to be installed
temp_pkg_dir() do
Pkg.generate("PackageWithTestDependencies", "MIT")
@test [keys(Pkg.installed())...] == ["PackageWithTestDependencies"]

open(Pkg.dir("PackageWithTestDependencies","REQUIRE"),"a") do f
println(f,"@test Example")
end

open(Pkg.dir("PackageWithTestDependencies","run_tests.jl"),"w") do f
println(f,"")
end

Pkg.resolve()
@test [keys(Pkg.installed())...] == ["PackageWithTestDependencies"]

Pkg.test("PackageWithTestDependencies")
@test sort([keys(Pkg.installed())...]) == sort(["PackageWithTestDependencies", "Example"])
end

# testing a package with no run_test.jl errors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runtest

temp_pkg_dir() do
Pkg.generate("PackageWithNoTests", "MIT")

try
Pkg.test("PackageWithNoTests")
catch err
@test err.msg == "PackageWithNoTests did not provide a run_test.jl file"
end
end

# testing a package with failing tests errors
temp_pkg_dir() do
Pkg.generate("PackageWithFailingTests", "MIT")

open(Pkg.dir("PackageWithFailingTests","run_tests.jl"),"w") do f
println(f,"using Base.Test")
println(f,"@test false")
end

try
Pkg.test("PackageWithFailingTests")
catch err
@test err.msg == "PackageWithFailingTests had test errors"
end
end