Skip to content

Commit 06e6900

Browse files
committed
Add tests and corresponding continuous integration
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.
1 parent 84a6aa7 commit 06e6900

File tree

7 files changed

+195
-0
lines changed

7 files changed

+195
-0
lines changed

Diff for: .travis.yml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Documentation: http://docs.travis-ci.com/user/languages/julia/
2+
language: julia
3+
os:
4+
- linux
5+
- osx
6+
julia:
7+
- 1.0
8+
- 1.1
9+
- 1.2
10+
- nightly
11+
before_install:
12+
- 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
13+
# If we want the Universal Ctags master. No tagged releases yet.
14+
# - if [ $TRAVIS_OS_NAME = osx ]; then brew tap universal-ctags/universal-ctags && brew install --HEAD universal-ctags; fi
15+
- if [ $TRAVIS_OS_NAME = osx ]; then brew install ctags; fi
16+
matrix:
17+
allow_failures:
18+
- julia: nightly
19+
notifications:
20+
email: false

Diff for: Project.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name = "julia-ctags"
2+
uuid = "106e64ca-b22d-11e9-257b-81adddf2616c"
3+
4+
[extras]
5+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
6+
7+
[targets]
8+
test = ["Test"]

Diff for: src/julia-ctags.jl

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# We need this file so this is recognized as a testable project...
2+

Diff for: test/runtests.jl

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Test
2+
3+
include("test_tags.jl")
4+
5+
function main()
6+
outputs = trygeneratetags(testfilepath)
7+
targets = gettargettags(testtagspath)
8+
# println("targets: ", targets)
9+
# println("outputs: ", outputs)
10+
testtags(targets, outputs)
11+
end
12+
13+
main()
14+

Diff for: test/test_tags.jl

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"Tags starting with this identifier are broken. Remove upon fix."
2+
const brokenidentifiers = (
3+
"deprecated_returnsquarepower",
4+
"deprecated_squarepower",
5+
"DocTestSetup",
6+
"printgreeting",
7+
"returnsquarepower",
8+
)
9+
"Kinds that have not been added yet (and are therefore broken). Remove upon fix."
10+
const brokenkinds = ('m', 's')
11+
12+
"Path to Ctags configuration file (the parser)."
13+
const ctagsconfigpath = joinpath(@__DIR__, "..", "ctags")
14+
"Test file to generate the tags from."
15+
const testfilepath = joinpath(@__DIR__, "testfile.jl")
16+
"File containing test tags to compare against."
17+
const testtagspath = joinpath(@__DIR__, "testtags")
18+
19+
"Ctags binaries to sequentially try to call if one is not found."
20+
const ctagsbins = (
21+
"ctags",
22+
"uctags",
23+
"ectags",
24+
"universal-ctags",
25+
"exuberant-ctags",
26+
"u-ctags",
27+
"e-ctags",
28+
)
29+
"Arguments to pass to a Ctags binary."
30+
const ctagsargs = (
31+
"--options=$ctagsconfigpath", # Include our tags file.
32+
"-f -" # Write to stdout.
33+
)
34+
35+
36+
"Utility function to convert an `AbstractVector` of tags to a common format."
37+
function converttags(tags::AbstractVector)
38+
tags = filter(s -> !isempty(s) && s[1] != '!', tags)
39+
Set(tags)
40+
end
41+
42+
"Return tags generatad from the given file and convert them using [`converttags`](@ref)."
43+
function generatetags(testfile::AbstractString, ctagsbin::AbstractString="ctags")
44+
ctagscmd = `$ctagsbin $ctagsargs $testfile`
45+
tags = open(ctagscmd, "r", stdout) do io
46+
readlines(io)
47+
end
48+
return converttags(tags)
49+
end
50+
51+
function trygeneratetags(testfile::AbstractString)
52+
for ctagsbinary in ctagsbins
53+
try
54+
return generatetags(testfile, ctagsbinary)
55+
catch e
56+
# For compatibility accept either exception type.
57+
if !(err isa LoadError || err isa ErrorException
58+
|| err isa ProcessFailedException)
59+
rethrow()
60+
end
61+
end
62+
end
63+
end
64+
65+
"""
66+
Return tags to compare against.
67+
The desired output of the Ctags program applied to [`testfilepath`](@ref).
68+
"""
69+
function gettargettags(testtags::AbstractString)
70+
tags = readlines(testtags)
71+
converttags(tags)
72+
end
73+
74+
75+
"Return the path listed in the output tags."
76+
function getpath(outputs)
77+
# We are operating on a set, so we cannot use `lastindex`.
78+
refoutput = pop!(outputs)
79+
push!(outputs, refoutput)
80+
path = split(refoutput, '\t')[2]
81+
end
82+
83+
"Return whether the given tag should be evaluated using [`test_broken`](@ref)."
84+
function isbroken(target)
85+
columns = split(target, '\t')
86+
return columns[1] in brokenidentifiers || columns[4][1] in brokenkinds
87+
end
88+
89+
"Replace the path listed in the given tag with the given path."
90+
function replacepath(tag, path)
91+
arraytag = split(tag, '\t')
92+
arraytag[2] = path
93+
return join(arraytag, '\t')
94+
end
95+
96+
97+
"""
98+
Test whether the given target is in the given outputs.
99+
The target's listed path is replaced with `outputpath` to ensure static tests.
100+
"""
101+
function test_target_in_outputs(target, outputs, outputpath)
102+
target = replacepath(target, outputpath)
103+
target_in_outputs = target in outputs
104+
105+
if isbroken(target)
106+
println("testing broken tag: ", target)
107+
result = @test_broken target_in_outputs
108+
else
109+
println("testing tag: ", target)
110+
result = @test target_in_outputs
111+
end
112+
target_in_outputs && delete!(outputs, target)
113+
end
114+
115+
"Test the two given tags against each other."
116+
function testtags(targets, outputs)
117+
outputpath = getpath(outputs)
118+
@testset "Tags" begin
119+
for target in targets
120+
test_target_in_outputs(target, outputs, outputpath)
121+
end
122+
@test_broken isempty(outputs)
123+
end
124+
end
125+

Diff for: testfile.jl renamed to test/testfile.jl

File renamed without changes.

Diff for: test/testtags

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
! A test file for ctags support. Manually written, do not overwrite.
2+
! For the kinds (fourth column), see the ctags file.
3+
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
4+
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
5+
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
6+
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
7+
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
8+
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
9+
!_TAG_PROGRAM_VERSION 0.0.0 /1a94658c/
10+
CtagsTest test/testfile.jl /^module CtagsTest$/;" m
11+
ImmutablePoint test/testfile.jl /^struct ImmutablePoint{T}$/;" s
12+
MutablePoint test/testfile.jl /^mutable struct MutablePoint{T}$/;" s
13+
Names test/testfile.jl /^Base.@kwdef struct Names$/;" s
14+
VariableNames test/testfile.jl /^Base.@kwdef mutable struct VariableNames$/;" s
15+
addcoment test/testfile.jl /^addcoment(string::AbstractString, comment, spaces=1) = begin # Maybe write without `begin`?$/;" f
16+
addone! test/testfile.jl /^function addone!(x::T) where {T <: Number}$/;" f
17+
addtwo! test/testfile.jl /^addtwo!(x::T) where {T <: Number} = (x += one(T) + one(T))$/;" f
18+
greet test/testfile.jl /^@generated function greet(x)$/;" f
19+
greeting test/testfile.jl /^const greeting = "Hello"$/;" v
20+
multiply test/testfile.jl /^multiply(x, y) = x * y$/;" f
21+
multiply test/testfile.jl /^multiply(x, y...) = begin$/;" f
22+
myconstsquarepower test/testfile.jl /^const myconstsquarepower = returnsquarepower()$/;" v
23+
mysquarepower test/testfile.jl /^mysquarepower = returnsquarepower()$/;" v
24+
returnsquarepower test/testfile.jl /^returnsquarepower = () -> 2$/;" f
25+
square test/testfile.jl /^function square(x)$/;" f
26+
squarepower test/testfile.jl /^squarepower = returnsquarepower$/;" v

0 commit comments

Comments
 (0)