Skip to content

Commit

Permalink
Improve test coverage (#465)
Browse files Browse the repository at this point in the history
This is designed to catch issues like what happened in #460, but also 
more generally improve test coverage.
  • Loading branch information
timholy authored Apr 24, 2020
1 parent 66380df commit b2c3463
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 91 deletions.
11 changes: 10 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,18 @@ git:

script:
- export JULIA_PROJECT=""
# Populate the precompile cache with an extraneous file, to catch issues like in #460
- julia -e 'include(joinpath("test", "populate_compiled.jl"))'
# Run the normal tests
- julia --project -e 'using Pkg; Pkg.build(); Pkg.test(; coverage=true);'
# The REPL wasn't initialized, so the "Methods at REPL" tests didn't run. Pick those up now.
- julia --project --code-coverage=user -e 'using InteractiveUtils, REPL, Revise; @async(Base.run_main_repl(true, true, false, true, false)); Revise.async_steal_repl_backend(); include(joinpath("test", "runtests.jl")); REPL.eval_user_input(:(exit()), Base.active_repl_backend)' "Methods at REPL"
# We also need to pick up the Git tests, but for that we need to `dev` the package
- julia -e 'using Pkg; Pkg.develop(PackageSpec(path=".")); include(joinpath("test", "runtests.jl"))' "Git"
# Tests for when using polling
- JULIA_REVISE_POLL=1 julia --code-coverage=user --project -e 'using Pkg, Revise; include(joinpath(dirname(pathof(Revise)), "..", "test", "polling.jl"))'
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then echo 4 | sudo tee -a /proc/sys/fs/inotify/max_user_watches; julia --project -e 'using Pkg, Revise; cd(joinpath(dirname(pathof(Revise)), "..", "test")); include("inotify.jl")'; fi
# Running out of inotify storage (see #26)
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then echo 4 | sudo tee -a /proc/sys/fs/inotify/max_user_watches; julia --project --code-coverage=user -e 'using Pkg, Revise; cd(joinpath(dirname(pathof(Revise)), "..", "test")); include("inotify.jl")'; fi

after_success:
- julia -e 'import Pkg; Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'
Expand Down
3 changes: 1 addition & 2 deletions docs/src/dev_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,9 @@ Revise.revise_file_queued
Revise.revise_file_now
```

### Interchange between methods and signatures
### Caching the definition of methods

```@docs
Revise.get_method
Revise.get_def
```

Expand Down
2 changes: 1 addition & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ If Revise isn't working for you, here are some steps to try:
- Try running `test Revise` from the Pkg REPL-mode.
If tests pass, check the documentation to make sure you understand how Revise should work.
If they fail (especially if it mirrors functionality that you need and isn't working), see
[Fixing a broken or partially-working installation](@ref) for some suggestions.
[Debugging problems with paths](@ref) for one set of suggestions.

If you still encounter problems, please [file an issue](https://github.com/timholy/Revise.jl/issues).
Especially if you think Revise is making mistakes in adding or deleting methods, please
Expand Down
67 changes: 2 additions & 65 deletions src/Revise.jl
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@ struct CodeTrackingMethodInfo
includes::Vector{String}
end
CodeTrackingMethodInfo(ex::Expr) = CodeTrackingMethodInfo([ex], Any[], Set{Union{GlobalRef,Symbol}}(), String[])
CodeTrackingMethodInfo(rex::RelocatableExpr) = CodeTrackingMethodInfo(rex.ex)

function add_signature!(methodinfo::CodeTrackingMethodInfo, @nospecialize(sig), ln)
CodeTracking.method_info[sig] = (fixpath(ln), methodinfo.exprstack[end])
Expand Down Expand Up @@ -473,7 +472,6 @@ function init_watching(pkgdata::PkgData, files)
end
return nothing
end
init_watching(files) = init_watching(PkgId(Main), files)

"""
revise_dir_queued(dirname)
Expand Down Expand Up @@ -563,9 +561,10 @@ that move from one file to another.
`Revise.pkgdatas[id].fileinfos`.
"""
function revise_file_now(pkgdata::PkgData, file)
# @assert !isabspath(file)
i = fileindex(pkgdata, file)
if i === nothing
println("Revise is currently tracking the following files in $(pkgdata.id): ", keys(pkgdict))
println("Revise is currently tracking the following files in $(PkgId(pkgdata)): ", srcfiles(pkgdata))
error(file, " is not currently being tracked.")
end
mexsnew, mexsold = handle_deletions(pkgdata, file)
Expand Down Expand Up @@ -850,49 +849,6 @@ silence(pkg::AbstractString) = silence(Symbol(pkg))

## Utilities

"""
method = get_method(sigt)
Get the method `method` with signature-type `sigt`. This is used to provide
the method to `Base.delete_method`.
If `sigt` does not correspond to a method, returns `nothing`.
# Examples
```jldoctest; setup = :(using Revise), filter = r"in Main at.*"
julia> mymethod(::Int) = 1
mymethod (generic function with 1 method)
julia> mymethod(::AbstractFloat) = 2
mymethod (generic function with 2 methods)
julia> Revise.get_method(Tuple{typeof(mymethod), Int})
mymethod(::Int64) in Main at REPL[0]:1
julia> Revise.get_method(Tuple{typeof(mymethod), Float64})
mymethod(::AbstractFloat) in Main at REPL[1]:1
julia> Revise.get_method(Tuple{typeof(mymethod), Number})
```
"""
function get_method(@nospecialize(sigt))
mths = Base._methods_by_ftype(sigt, -1, typemax(UInt))
length(mths) == 1 && return mths[1][3]
if !isempty(mths)
# There might be many methods, but the one that should match should be the
# last one, since methods are ordered by specificity
i = lastindex(mths)
while i > 0
m = mths[i][3]
m.sig == sigt && return m
i -= 1
end
end
return nothing
end

"""
success = get_def(method::Method)
Expand Down Expand Up @@ -999,25 +955,6 @@ function add_definitions_from_repl(filename)
return fi
end

function fix_line_statements!(ex::Expr, file::Symbol, line_offset::Int=0)
if ex.head == :line
ex.args[1] += line_offset
ex.args[2] = file
else
for (i, a) in enumerate(ex.args)
if isa(a, Expr)
fix_line_statements!(a::Expr, file, line_offset)
elseif isa(a, LineNumberNode)
ex.args[i] = file_line_statement(a::LineNumberNode, file, line_offset)
end
end
end
ex
end

file_line_statement(lnn::LineNumberNode, file::Symbol, line_offset) =
LineNumberNode(lnn.line + line_offset, file)

function update_stacktrace_lineno!(trace)
local nrep
for i = 1:length(trace)
Expand Down
7 changes: 7 additions & 0 deletions src/backedges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ function toplevel_chunks(backedges::BackEdges)
return chunks
end

"""
hastrackedexpr(src, chunk=1:length(src.code))
Detect whether the specified `chunk` of `src` contains a definition tracked
by Revise. By default these are methods and type definitions (the latter because
they might contain constructors).
"""
function hastrackedexpr(code::CodeInfo, chunk::AbstractUnitRange=axes(code.code, 1); heads=(:method, :struct_type, :abstract_type, :primitive_type))
for stmtidx in chunk
stmt = code.code[stmtidx]
Expand Down
18 changes: 1 addition & 17 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,6 @@ Base.in(file, wl::WatchList) = haskey(wl.trackedfiles, file)
newer(mtime, timestamp) = mtime >= timestamp
end

function macroreplace!(ex::Expr, filename)
for i = 1:length(ex.args)
ex.args[i] = macroreplace!(ex.args[i], filename)
end
if ex.head == :macrocall
m = ex.args[1]
if m == Symbol("@__FILE__")
return String(filename)
elseif m == Symbol("@__DIR__")
return dirname(String(filename))
end
end
return ex
end
macroreplace!(s, filename) = s

function printf_maxsize(f::Function, io::IO, args...; maxchars::Integer=500, maxlines::Integer=20)
# This is dumb but certain to work
iotmp = IOBuffer()
Expand Down Expand Up @@ -144,7 +128,7 @@ function printf_maxsize(f::Function, io::IO, args...; maxchars::Integer=500, max
end
end
println_maxsize(args...; kwargs...) = println_maxsize(stdout, args...; kwargs...)
println_maxsize(io::IO, args...; kwargs...) = printf_maxsize(println, stdout, args...; kwargs...)
println_maxsize(io::IO, args...; kwargs...) = printf_maxsize(println, io, args...; kwargs...)

# Trimming backtraces
function trim_toplevel!(bt)
Expand Down
16 changes: 16 additions & 0 deletions test/populate_compiled.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This runs only on Travis. The goal is to populate the `.julia/compiled/v*` directory
# with some additional files, so that `filter_valid_cachefiles` has to run.
# This is to catch problems like #460.

using Pkg
using Test

Pkg.add(PackageSpec(name="EponymTuples", version="0.2.0"))
using EponymTuples # force compilation
id = Base.PkgId(EponymTuples)
paths = Base.find_all_in_cache_path(id)
Pkg.rm("EponymTuples") # we don't need it anymore
path = first(paths)
base, ext = splitext(path)
mv(path, base*"blahblah"*ext)
Pkg.add(PackageSpec(name="EponymTuples"))
Loading

0 comments on commit b2c3463

Please sign in to comment.