Skip to content

Commit

Permalink
Add tests and corresponding continuous integration
Browse files Browse the repository at this point in the history
Many tests are still marked as broken.
The test/testtags file contains the desired tags to obtain. Some need
only a little work, some need a more complete parser than the current
argument-regex-based approach.

We could possibly use the master of Universal Ctags for MacOS but that
would introduce another error surface.
  • Loading branch information
janEbert committed Oct 24, 2019
1 parent 84a6aa7 commit a92bcbd
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Documentation: http://docs.travis-ci.com/user/languages/julia/
language: julia
os:
- linux
- osx
julia:
- 1.0
- 1.1
- 1.2
- nightly
before_install:
- if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install -y universal-ctags || sudo apt-get install -y exuberant-ctags || sudo apt-get install -y ctags; fi
# If we want the Universal Ctags master. No tagged releases yet.
# - if [ $TRAVIS_OS_NAME = osx ]; then brew tap universal-ctags/universal-ctags && brew install --HEAD universal-ctags; fi
- if [ $TRAVIS_OS_NAME = osx ]; then brew install ctags; fi
matrix:
allow_failures:
- julia: nightly
notifications:
email: false
8 changes: 8 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name = "julia-ctags"
uuid = "106e64ca-b22d-11e9-257b-81adddf2616c"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
2 changes: 2 additions & 0 deletions src/julia-ctags.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# We need this file so this is recognized as a testable project...

14 changes: 14 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Test

include("test_tags.jl")

function main()
outputs = trygeneratetags(testfilepath)
targets = gettargettags(testtagspath)
# println("targets: ", targets)
# println("outputs: ", outputs)
testtags(targets, outputs)
end

main()

125 changes: 125 additions & 0 deletions test/test_tags.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"Tags starting with this identifier are broken. Remove upon fix."
const brokenidentifiers = (
"deprecated_returnsquarepower",
"deprecated_squarepower",
"DocTestSetup",
"printgreeting",
"returnsquarepower",
)
"Kinds that have not been added yet (and are therefore broken). Remove upon fix."
const brokenkinds = ('m', 's')

"Path to Ctags configuration file (the parser)."
const ctagsconfigpath = joinpath(@__DIR__, "..", "ctags")
"Test file to generate the tags from."
const testfilepath = joinpath(@__DIR__, "testfile.jl")
"File containing test tags to compare against."
const testtagspath = joinpath(@__DIR__, "testtags")

"Ctags binaries to sequentially try to call if one is not found."
const ctagsbins = (
"uctags",
"ectags",
"universal-ctags",
"exuberant-ctags",
"u-ctags",
"e-ctags",
"ctags",
)
"Arguments to pass to a Ctags binary."
const ctagsargs = (
"--options=$ctagsconfigpath", # Include our tags file.
"-f -" # Write to stdout.
)


"Utility function to convert an `AbstractVector` of tags to a common format."
function converttags(tags::AbstractVector)
tags = filter(s -> !isempty(s) && s[1] != '!', tags)
Set(tags)
end

"Return tags generatad from the given file and convert them using [`converttags`](@ref)."
function generatetags(testfile::AbstractString, ctagsbin::AbstractString="ctags")
ctagscmd = `$ctagsbin $ctagsargs $testfile`
tags = open(ctagscmd, "r", stdout) do io
readlines(io)
end
return converttags(tags)
end

function trygeneratetags(testfile::AbstractString)
for ctagsbinary in ctagsbins
try
return generatetags(testfile, ctagsbinary)
catch e
# For compatibility accept either exception type.
if !(err isa LoadError || err isa ErrorException
|| err isa ProcessFailedException)
rethrow()
end
end
end
end

"""
Return tags to compare against.
The desired output of the Ctags program applied to [`testfilepath`](@ref).
"""
function gettargettags(testtags::AbstractString)
tags = readlines(testtags)
converttags(tags)
end


"Return the path listed in the output tags."
function getpath(outputs)
# We are operating on a set, so we cannot use `lastindex`.
refoutput = pop!(outputs)
push!(outputs, refoutput)
path = split(refoutput, '\t')[2]
end

"Return whether the given tag should be evaluated using [`test_broken`](@ref)."
function isbroken(target)
columns = split(target, '\t')
return columns[1] in brokenidentifiers || columns[4][1] in brokenkinds
end

"Replace the path listed in the given tag with the given path."
function replacepath(tag, path)
arraytag = split(tag, '\t')
arraytag[2] = path
return join(arraytag, '\t')
end


"""
Test whether the given target is in the given outputs.
The target's listed path is replaced with `outputpath` to ensure static tests.
"""
function test_target_in_outputs(target, outputs, outputpath)
target = replacepath(target, outputpath)
target_in_outputs = target in outputs

if isbroken(target)
println("testing broken tag: ", target)
result = @test_broken target_in_outputs
else
println("testing tag: ", target)
result = @test target_in_outputs
end
target_in_outputs && delete!(outputs, target)
end

"Test the two given tags against each other."
function testtags(targets, outputs)
outputpath = getpath(outputs)
@testset "Tags" begin
for target in targets
test_target_in_outputs(target, outputs, outputpath)
end
@test_broken isempty(outputs)
end
end

File renamed without changes.
26 changes: 26 additions & 0 deletions test/testtags
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
! A test file for ctags support. Manually written, do not overwrite.
! For the kinds (fourth column), see the ctags file.
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 0.0.0 /1a94658c/
CtagsTest test/testfile.jl /^module CtagsTest$/;" m
ImmutablePoint test/testfile.jl /^struct ImmutablePoint{T}$/;" s
MutablePoint test/testfile.jl /^mutable struct MutablePoint{T}$/;" s
Names test/testfile.jl /^Base.@kwdef struct Names$/;" s
VariableNames test/testfile.jl /^Base.@kwdef mutable struct VariableNames$/;" s
addcoment test/testfile.jl /^addcoment(string::AbstractString, comment, spaces=1) = begin # Maybe write without `begin`?$/;" f
addone! test/testfile.jl /^function addone!(x::T) where {T <: Number}$/;" f
addtwo! test/testfile.jl /^addtwo!(x::T) where {T <: Number} = (x += one(T) + one(T))$/;" f
greet test/testfile.jl /^@generated function greet(x)$/;" f
greeting test/testfile.jl /^const greeting = "Hello"$/;" v
multiply test/testfile.jl /^multiply(x, y) = x * y$/;" f
multiply test/testfile.jl /^multiply(x, y...) = begin$/;" f
myconstsquarepower test/testfile.jl /^const myconstsquarepower = returnsquarepower()$/;" v
mysquarepower test/testfile.jl /^mysquarepower = returnsquarepower()$/;" v
returnsquarepower test/testfile.jl /^returnsquarepower = () -> 2$/;" f
square test/testfile.jl /^function square(x)$/;" f
squarepower test/testfile.jl /^squarepower = returnsquarepower$/;" v

0 comments on commit a92bcbd

Please sign in to comment.