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

Refactor Runic.main tests to also cover juliac code paths #104

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ jobs:
- uses: julia-actions/cache@v2
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
with:
directories: "src,juliac"
- uses: codecov/codecov-action@v4
with:
file: lcov.info
Expand Down
366 changes: 366 additions & 0 deletions test/maintests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
# SPDX-License-Identifier: MIT

using Test: @test
using Runic: Runic

function maintests(f::R) where {R}

bad = "1+1"
good = "1 + 1\n"

# Utils
function cdtmp(f)
return mktempdir(tmp -> cd(f, tmp))
end
function runic(std_in::String)
return runic(String[], std_in)
end
function runic(argv::Vector{String} = String[], std_in::String = "")
rc, stdout_str, stderr_str = mktemp() do stdin_path, stdin
write(stdin_path, std_in)
mktemp() do stdout_path, stdout
mktemp() do stderr_path, stderr
rc = redirect_stdio(() -> f(copy(argv)); stdin, stdout, stderr)
close(stderr)
close(stdout)
return rc, read(stdout_path, String), read(stderr_path, String)
end
end
end
return rc, stdout_str, stderr_str
end

# runic --help
let (rc, fd1, fd2) = runic(["--help"])
@test rc == 0
@test occursin("Runic.main - format Julia source code", fd1)
@test isempty(fd2)
end

# runic --version
let (rc, fd1, fd2) = runic(["--version"])
@test rc == 0
@test occursin("runic version $(Runic.RUNIC_VERSION), julia version $(VERSION)", fd1)
@test isempty(fd2)
end

# runic <stdin >stdout
for argv in [
String[], ["-"],
["--output=-"], ["-o", "-"],
["--output=-", "-"], ["-o", "-", "-"],
]
rc, fd1, fd2 = runic(argv, bad)
@test rc == 0
@test occursin(good, fd1)
@test isempty(fd2)
end

# runic --output=out.jl <stdin
cdtmp() do
f_out = "out.jl"
for argv in [
["--output=$f_out"], ["-o", f_out],
["--output=$f_out", "-"], ["-o", f_out, "-"],
]
rm(f_out, force = true)
rc, fd1, fd2 = runic(argv, bad)
@test rc == 0
@test isempty(fd1)
@test isempty(fd2)
@test read(f_out, String) == good
end
end

# runic in.jl >stdout
cdtmp() do
f_in = "in.jl"
write(f_in, bad)
for argv in [[f_in], ["--output=-", f_in], ["-o", "-", f_in]]
rc, fd1, fd2 = runic(argv)
@test rc == 0
@test occursin(good, fd1)
@test isempty(fd2)
@test read(f_in, String) == bad
end
end

# runic --output=out.jl in.jl
cdtmp() do
f_in = "in.jl"
write(f_in, bad)
f_out = "out.jl"
for argv in [["--output=$f_out", f_in], ["-o", f_out, f_in]]
rm(f_out, force = true)
rc, fd1, fd2 = runic(argv)
@test rc == 0
@test isempty(fd1)
@test occursin("Formatting `in.jl` -> `out.jl` ...", fd2)
@test occursin("✔", fd2)
@test !occursin("✖", fd2)
@test read(f_out, String) == good
@test read(f_in, String) == bad
end
end

# runic --inplace in.jl (bad input)
cdtmp() do
f_in = "in.jl"
for argv in [["--inplace", f_in], ["-i", f_in]]
write(f_in, bad)
rc, fd1, fd2 = runic(argv)
@test rc == 0
@test isempty(fd1)
@test occursin("Formatting `in.jl` ...", fd2)
@test occursin("✔", fd2)
@test !occursin("✖", fd2)
@test read(f_in, String) == good
end
end

# runic --inplace in.jl (good input)
cdtmp() do
f_in = "in.jl"
for argv in [["--inplace", f_in], ["-i", f_in]]
write(f_in, good)
rc, fd1, fd2 = runic(argv)
@test rc == 0
@test isempty(fd1)
@test occursin("Formatting `in.jl` ...", fd2)
@test occursin("✔", fd2)
@test !occursin("✖", fd2)
@test read(f_in, String) == good
end
end

# runic --inplace in/
cdtmp() do
fgood = "good.jl"
mkdir("src")
fbad = joinpath("src", "bad.jl")
mkdir(".git")
gitfile = joinpath(".git", "git.jl")
write(gitfile, "this is not a Julia file")
markdownfile = "markdown.md"
write(markdownfile, "this is not a Julia file")
for argv in [["--inplace", "."], ["-i", "."], ["-i", ".", "src"]]
write(fgood, good)
write(fbad, bad)
rc, fd1, fd2 = runic(argv)
@test rc == 0
@test isempty(fd1)
@test occursin("Formatting `good.jl` ...", fd2)
@test occursin("Formatting `src/bad.jl` ...", fd2)
@test occursin("✔", fd2)
@test !occursin("✖", fd2)
@test !occursin("git.jl", fd2)
@test !occursin("markdown.jl", fd2)
@test read(fgood, String) == read(fbad, String) == good
end
end

# runic --check in.jl (bad input)
cdtmp() do
f_in = "in.jl"
for argv in [["--check", f_in], ["-c", f_in]]
write(f_in, bad)
rc, fd1, fd2 = runic(argv)
@test rc == 1
@test isempty(fd1)
@test occursin("Checking `in.jl` ...", fd2)
@test !occursin("✔", fd2)
@test occursin("✖", fd2)
@test read(f_in, String) == bad
end
end

# runic --check in.jl (good input)
cdtmp() do
f_in = "in.jl"
for argv in [["--check", f_in], ["-c", f_in]]
write(f_in, good)
rc, fd1, fd2 = runic(argv)
@test rc == 0
@test isempty(fd1)
@test occursin("Checking `in.jl` ...", fd2)
@test occursin("✔", fd2)
@test !occursin("✖", fd2)
@test read(f_in, String) == good
end
end

# runic --check in/
cdtmp() do
fgood = "good.jl"
mkdir("src")
fbad = joinpath("src", "bad.jl")
mkdir(".git")
gitfile = joinpath(".git", "git.jl")
write(gitfile, "this is not a Julia file")
markdownfile = "markdown.md"
write(markdownfile, "this is not a Julia file")
for argv in [["--check", "."], ["-c", "."]]
write(fgood, good)
write(fbad, bad)
rc, fd1, fd2 = runic(argv)
@test rc == 1
@test isempty(fd1)
@test occursin("Checking `good.jl` ...", fd2)
@test occursin("Checking `src/bad.jl` ...", fd2)
@test occursin("✔", fd2)
@test occursin("✖", fd2)
@test !occursin("git.jl", fd2)
@test !occursin("markdown.jl", fd2)
@test read(fgood, String) == good
@test read(fbad, String) == bad
end
end

# runic --check --diff in.jl
if Sys.which("git") !== nothing
cdtmp() do
f_in = "in.jl"
for argv in [["--check", "--diff", f_in], ["-c", "-d", f_in]]
write(f_in, bad)
rc, fd1, fd2 = runic(argv)
@test rc == 1
@test isempty(fd1)
@test occursin("Checking `in.jl` ...", fd2)
@test !occursin("✔", fd2)
@test occursin("✖", fd2)
@test occursin("diff --git", fd2)
@test occursin("-1+1", fd2)
@test occursin("+1 + 1", fd2)
@test read(f_in, String) == bad
end
end
end

# Error paths
# runic -o
let (rc, fd1, fd2) = runic(["-o"])
@test rc == 1
@test isempty(fd1)
@test occursin("expected output file argument after `-o`", fd2)
end

# runic in.jl -
let (rc, fd1, fd2) = runic(["in.jl", "-"])
@test rc == 1
@test isempty(fd1)
@test occursin("input `-` can not be used with multiple files", fd2)
end

# runic --inplace --check (TODO: perhaps this should be allowed?)
let (rc, fd1, fd2) = runic(["--inplace", "--check"])
@test rc == 1
@test isempty(fd1)
@test occursin("options `--inplace` and `--check` are mutually exclusive", fd2)
end

# runic --inplace --output=out.jl in.jl
let (rc, fd1, fd2) = runic(["--inplace", "--output=out.jl", "in.jl"])
@test rc == 1
@test isempty(fd1)
@test occursin("options `--inplace` and `--output` are mutually exclusive", fd2)
end

# runic --check --output=out.jl in.jl
let (rc, fd1, fd2) = runic(["--check", "--output=out.jl", "in.jl"])
@test rc == 1
@test isempty(fd1)
@test occursin("options `--check` and `--output` are mutually exclusive", fd2)
end

# runic --inplace
let (rc, fd1, fd2) = runic(["--inplace"])
@test rc == 1
@test isempty(fd1)
@test occursin("option `--inplace` can not be used together with stdin input", fd2)
end

# runic --output=out.jl in1.jl in2.jl
let (rc, fd1, fd2) = runic(["--output=out.jl", "in1.jl", "in2.jl"])
@test rc == 1
@test isempty(fd1)
@test occursin("option `--output` can not be used together with multiple input files", fd2)
end

# runic in1.jl in2.jl
let (rc, fd1, fd2) = runic(["in1.jl", "in2.jl"])
@test rc == 1
@test isempty(fd1)
@test occursin("option `--inplace` or `--check` required with multiple input files", fd2)
end

# runic --diff (with no git)
let (rc, fd1, fd2) = withenv(() -> runic(["--diff"]), "PATH" => "")
@test rc == 1
@test isempty(fd1)
@test occursin("option `--diff` requires `git` to be installed", fd2)
end

# runic in.jl (not readable)
cdtmp() do
f_in = "in.jl"
write(f_in, bad)
omode = filemode(f_in)
chmod(f_in, omode & (typemax(omode) ⊻ 0o444))
rc, fd1, fd2 = runic([f_in])
chmod(f_in, omode)
@test rc == 1
@test isempty(fd1)
@test occursin("could not read input from file", fd2)
@test occursin("SystemError: opening file", fd2)
end

# runic doesntexist.jl
cdtmp() do
rc, fd1, fd2 = runic(["doesntexist.jl"])
@test rc == 1
@test isempty(fd1)
@test occursin("input file does not exist", fd2)
end

# runic -o in.jl in.jl
cdtmp() do
f_in = "in.jl"
write(f_in, bad)
rc, fd1, fd2 = runic(["-o", f_in, f_in])
@test rc == 1
@test isempty(fd1)
@test occursin("can not use same file for input and output", fd2)
end

# runic --check unparseable.jl
cdtmp() do
f_in = "in.jl"
write(f_in, "syntax error")
rc, fd1, fd2 = runic(["--check", f_in])
@test rc == 1
@test isempty(fd1)
@test occursin("failed to parse input", fd2)
end

# runic -o readonly.jl in.jl
return cdtmp() do
f_in = "in.jl"
write(f_in, bad)
f_out = "readonly.jl"
touch(f_out)
omode = filemode(f_out)
chmod(f_out, omode & (typemax(omode) ⊻ 0o222))
rc, fd1, fd2 = runic(["-o", f_out, f_in])
chmod(f_out, omode)
@test rc == 1
@test isempty(fd1)
@test occursin("could not write to output file", fd2)
end
end

# rc = let argv = pushfirst!(copy(argv), "runic"), argc = length(argv) % Cint
# GC.@preserve argv begin
# argvptr = Base.unsafe_convert(Ptr{Ptr{UInt8}}, Base.cconvert(Ptr{Ptr{UInt8}}, argv))
# redirect_stdio(() -> Main.RunicC.main(argc, argvptr); stdin, stdout, stderr)
# end
# end
Loading