Skip to content

Commit

Permalink
Merge pull request #12 from JuliaDebug/teh/juliatests
Browse files Browse the repository at this point in the history
Add test harness for running all of Julia's tests
  • Loading branch information
timholy authored Feb 10, 2019
2 parents 3015557 + 137e6a7 commit 62bb82a
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 0 deletions.
59 changes: 59 additions & 0 deletions test/juliatests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using JuliaInterpreter
using Test

if !isdefined(Main, :read_and_parse)
include("utils.jl")
end

const juliadir = dirname(dirname(Sys.BINDIR))
const testdir = joinpath(juliadir, "test")
if isdir(testdir)
include(joinpath(testdir, "choosetests.jl"))
else
@warn "Julia's test/ directory not found, skipping Julia tests"
end

module JuliaTests end

@testset "Julia tests" begin
stack = JuliaStackFrame[]
function runtest(frame)
empty!(stack)
empty!(JuliaInterpreter.framedict)
empty!(JuliaInterpreter.genframedict)
return JuliaInterpreter.finish_and_return!(stack, frame, true)
end
function dotest!(failed, test)
println("Working on ", test, "...")
ex = read_and_parse(joinpath(testdir, test)*".jl")
if isexpr(ex, :error)
@warn "error parsing $test: $ex"
else
ex = Expr(:toplevel, :(using Test), ex)
try
lower_incrementally(runtest, JuliaTests, ex)
println("Succeeded on ", test)
catch err
@show test err
push!(failed, (test, err))
end
end
end
if isdir(testdir)
tests, _ = choosetests()
delayed = []
failed = []
for test in tests
if startswith(test, "compiler")
push!(delayed, test)
else
dotest!(failed, test)
end
end
for test in delayed
dotest!(failed, test)
end
@show failed
@test isempty(failed)
end
end
77 changes: 77 additions & 0 deletions test/utils.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using JuliaInterpreter: JuliaStackFrame, finish_and_return!
using Base.Meta: isexpr

# Execute a frame using Julia's regular compiled-code dispatch for any :call expressions
runframe(frame, pc=frame.pc[]) = Some{Any}(finish_and_return!(Compiled(), frame, pc))
Expand All @@ -8,3 +9,79 @@ function runstack(frame::JuliaStackFrame, pc=frame.pc[])
stack = JuliaStackFrame[]
return Some{Any}(finish_and_return!(stack, frame, pc))
end

## For juliatests.jl

isdocexpr(ex) = isexpr(ex, :macrocall) && (a = ex.args[1]; a isa GlobalRef && a.mod == Core && a.name == Symbol("@doc"))

function read_and_parse(filename)
src = read(filename, String)
ex = Base.parse_input_line(src; filename=filename)
end

"""
docexprs = lower_incrementally(f, mod::Module, ex::Expr)
Lower the sub-expressions of `ex` one-by-one, passing the `frame`s to `f(frame)`.
Any docstring-expressions encountered while processing module `M` (which might be `mod`
or one of its sub-modules) get returned in `docexprs[M]`.
"""
function lower_incrementally(@nospecialize(f), mod::Module, ex::Expr)
docexprs = Dict{Module,Vector{Expr}}()
lower_incrementally!(f, docexprs, mod, ex)
return docexprs
end

lower_incrementally!(@nospecialize(f), docexprs, mod::Module, ex::Expr) =
lower_incrementally!(f, docexprs, Expr(:block), mod, ex)

function lower_incrementally!(@nospecialize(f), docexprs, lex:: Expr, mod::Module, ex::Expr)
# lex is the expression we'll lower; it will accumulate LineNumberNodes and a
# single top-level expression. We split blocks, module defs, etc.
if ex.head == :toplevel || ex.head == :block
lower_incrementally!(f, docexprs, lex, mod, ex.args)
elseif ex.head == :module
modname = ex.args[2]::Symbol
newmod = isdefined(mod, modname) ? getfield(mod, modname) : Core.eval(mod, :(module $modname end))
lower_incrementally!(f, docexprs, lex, newmod, ex.args[3])
elseif isdocexpr(ex) && length(ex.args) >= 4
docexs = get(docexprs, mod, nothing)
if docexs === nothing
docexs = docexprs[mod] = Expr[]
end
push!(docexs, ex)
body = ex.args[4]
if isa(body, Expr)
lower_incrementally!(f, docexprs, lex, mod, body)
end
else
push!(lex.args, ex)
lower!(f, docexprs, mod, lex)
empty!(lex.args)
end
return docexprs
end

function lower_incrementally!(@nospecialize(f), docexprs, lex, mod::Module, args::Vector{Any})
for a in args
if isa(a, Expr)
lower_incrementally!(f, docexprs, lex, mod, a)
else
push!(lex.args, a)
end
end
end

function lower!(@nospecialize(f), docexprs, mod::Module, ex::Expr)
lwr = Meta.lower(mod, ex)
if isexpr(lwr, :thunk)
frame = JuliaInterpreter.prepare_thunk(mod, lwr)
f(frame)
elseif isa(lwr, Expr) && (lwr.head == :export || lwr.head == :using || lwr.head == :import)
elseif isa(lwr, Symbol) || isa(lwr, Nothing)
else
@show mod ex
error("lowering did not produce a :thunk Expr")
end
return docexprs
end

0 comments on commit 62bb82a

Please sign in to comment.