From 5adde3ad7c5d0ce2e1297e4fe5c5a2e1f7610505 Mon Sep 17 00:00:00 2001 From: Chris de Graaf Date: Sat, 31 Aug 2019 17:33:33 +0700 Subject: [PATCH] Add some basic tests --- .gitignore | 8 ++-- .travis.yml | 3 ++ Manifest.toml | 6 --- Project.toml | 8 ++-- src/PkgTemplates.jl | 2 +- src/generate.jl | 1 - src/plugins/ci.jl | 17 ++++---- src/plugins/defaults.jl | 4 +- src/template.jl | 48 ++++++++++------------ test/fixtures/Basic/.gitignore.txt | 3 ++ test/fixtures/Basic/LICENSE.txt | 19 +++++++++ test/fixtures/Basic/Manifest.toml.txt | 2 + test/fixtures/Basic/Project.toml.txt | 13 ++++++ test/fixtures/Basic/README.md.txt | 1 + test/fixtures/Basic/src/Basic.jl.txt | 5 +++ test/fixtures/Basic/test/runtests.jl.txt | 6 +++ test/generate.jl | 25 ++++++++++++ test/runtests.jl | 32 +++++++++++++++ test/template.jl | 52 ++++++++++++++++++++++++ 19 files changed, 202 insertions(+), 53 deletions(-) create mode 100644 test/fixtures/Basic/.gitignore.txt create mode 100644 test/fixtures/Basic/LICENSE.txt create mode 100644 test/fixtures/Basic/Manifest.toml.txt create mode 100644 test/fixtures/Basic/Project.toml.txt create mode 100644 test/fixtures/Basic/README.md.txt create mode 100644 test/fixtures/Basic/src/Basic.jl.txt create mode 100644 test/fixtures/Basic/test/runtests.jl.txt create mode 100644 test/generate.jl create mode 100644 test/template.jl diff --git a/.gitignore b/.gitignore index 7be7ea3..de2e6ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -.DS_Store -*.jl.cov -*.jl.*.cov -*.jl.mem /docs/build/ /docs/site/ +.DS_Store +*.jl.*.cov +*.jl.cov +*.jl.mem diff --git a/.travis.yml b/.travis.yml index 8bcbbb8..e4d9dce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,9 @@ julia: - 1.2 - 1.3 - nightly +before_script: + - git config --global user.name Tester + - git config --global user.email te@st.er matrix: fast_finish: true allow_failures: diff --git a/Manifest.toml b/Manifest.toml index c709f1d..afff9f0 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -106,12 +106,6 @@ version = "0.2.11" deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -[[URIParser]] -deps = ["Test", "Unicode"] -git-tree-sha1 = "6ddf8244220dfda2f17539fa8c9de20d6c575b69" -uuid = "30578b45-9adc-5946-b283-645ec420af67" -version = "0.4.0" - [[UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" diff --git a/Project.toml b/Project.toml index 863df15..5e069c6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PkgTemplates" uuid = "14b8a8f1-9102-5b29-a752-f990bacb7fe1" authors = ["Chris de Graaf "] -version = "0.6.2" +version = "0.7.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" @@ -11,14 +11,14 @@ Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" -URIParser = "30578b45-9adc-5946-b283-645ec420af67" [compat] julia = "1" [extras] -Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +ReferenceTests = "324d217c-45ce-50fc-942e-d289b448e8cf" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Suppressor", "Test"] +test = ["Random", "ReferenceTests", "Test"] diff --git a/src/PkgTemplates.jl b/src/PkgTemplates.jl index 6d07a02..801958b 100644 --- a/src/PkgTemplates.jl +++ b/src/PkgTemplates.jl @@ -11,7 +11,6 @@ using REPL.TerminalMenus: MultiSelectMenu, RadioMenu, request using Mustache: entityMap, render using Parameters: @with_kw -using URIParser: URI export Template, @@ -36,5 +35,6 @@ abstract type Plugin end include("template.jl") include("generate.jl") include("plugin.jl") +# include("interactive.jl") end diff --git a/src/generate.jl b/src/generate.jl index d4469e1..cc5404a 100644 --- a/src/generate.jl +++ b/src/generate.jl @@ -6,7 +6,6 @@ Generate a package named `pkg` from a [`Template`](@ref). function (t::Template)(pkg::AbstractString) endswith(pkg, ".jl") && (pkg = pkg[1:end-3]) pkg_dir = joinpath(t.dir, pkg) - ispath(pkg_dir) && throw(ArgumentError("$pkg_dir already exists")) try # Create the directory with some boilerplate inside. diff --git a/src/plugins/ci.jl b/src/plugins/ci.jl index b6ad606..b792ef4 100644 --- a/src/plugins/ci.jl +++ b/src/plugins/ci.jl @@ -1,14 +1,13 @@ -# TODO: Update the allowed failures as new versions come out. const VersionsOrStrings = Vector{Union{VersionNumber, String}} -const ALLOWED_FAILURES = ["1.3", "nightly"] -const DEFAULT_CI_VERSIONS = VersionsOrStrings([VERSION, "1.0", "nightly"]) +const ALLOWED_FAILURES = ["1.3", "nightly"] # TODO: Update this list with new RCs. +const DEFAULT_CI_VERSIONS = VersionsOrStrings([VERSION, default_version(), "nightly"]) format_version(v::VersionNumber) = "$(v.major).$(v.minor)" format_version(v::AbstractString) = string(v) function collect_versions(t::Template, versions::Vector) - vs = [format_version(t.julia_version); map(format_version, versions)] - return unique!(sort!(vs)) + vs = map(format_version, [t.julia_version, versions...]) + return unique(sort(vs)) end @with_kw struct TravisCI <: BasicPlugin @@ -43,8 +42,8 @@ function view(p::TravisCI, t::Template, pkg::AbstractString) x86 = Dict{String, String}[] if p.x86 foreach(versions) do v - p.linux && push!(x86, Dict("JULIA" => v, "OS" => "linux", "ARCH" => "x86")) - p.windows && push!(x86, Dict("JULIA" => v, "OS" => "windows", "ARCH" => "x86")) + p.linux && push!(x86, Dict("JULIA" => v, "OS" => "linux")) + p.windows && push!(x86, Dict("JULIA" => v, "OS" => "windows")) end end @@ -128,10 +127,10 @@ function view(p::CirrusCI, t::Template, ::AbstractString) end @with_kw struct GitLabCI <: BasicPlugin - file::String + file::String = default_file("gitlab-ci.yml") documentation::Bool = true coverage::Bool = true - extra_versions::Vector{VersionNumber} = [v"1.0"] + extra_versions::VersionsOrStrings = ["1.0"] # Nightly has no Docker image. end gitignore(p::GitLabCI) = p.coverage ? COVERAGE_GITIGNORE : String[] diff --git a/src/plugins/defaults.jl b/src/plugins/defaults.jl index 5f61413..2c4d596 100644 --- a/src/plugins/defaults.jl +++ b/src/plugins/defaults.jl @@ -93,7 +93,7 @@ function render_plugin(p::Gitignore, t::Template) end function gen_plugin(p::Gitignore, t::Template, pkg_dir::AbstractString) - gen_file(joinpath(pkg_dir, ".gitignore"), render_plugin(p, t)) + t.git && gen_file(joinpath(pkg_dir, ".gitignore"), render_plugin(p, t)) end @with_kw struct Tests <: BasicPlugin @@ -121,7 +121,7 @@ function gen_plugin(p::Tests, t::Template, pkg_dir::AbstractString) proj = current_project() try Pkg.activate(pkg_dir) - Pkg.update() # Clean up both Manifest.toml and Project.toml. + Pkg.update() finally proj === nothing ? Pkg.activate() : Pkg.activate(proj) end diff --git a/src/template.jl b/src/template.jl index 2d8f3dc..72dc581 100644 --- a/src/template.jl +++ b/src/template.jl @@ -1,13 +1,12 @@ -const DEFAULT_USER = LibGit2.getconfig("github.user", "") -const DEFAULT_VERSION = VersionNumber(VERSION.major) -const DEFAULT_AUTHORS = let +default_plugins() = [Gitignore(), License(), Readme(), Tests()] +default_user() = LibGit2.getconfig("github.user", "") +default_version() = VersionNumber(VERSION.major) + +function default_authors() name = LibGit2.getconfig("user.name", "") + isempty(name) && return "" email = LibGit2.getconfig("user.email", "") - if isempty(name) - "" - else - isempty(email) ? name : "$name <$email>" - end + return isempty(email) ? name : "$name <$email>" end """ @@ -18,17 +17,17 @@ Records common information used to generate a package. ## Keyword Arguments ### User Options -- `user::AbstractString="$DEFAULT_USER"`: GitHub (or other code hosting service) username. +- `user::AbstractString="$(default_user())"`: GitHub (or other code hosting service) username. The default value comes from the global Git config (`github.user`). If no value is obtained, an `ArgumentError` is thrown. -- `authors::Union{AbstractString, Vector{<:AbstractString}}="$DEFAULT_AUTHORS"`: Package authors. +- `authors::Union{AbstractString, Vector{<:AbstractString}}="$(default_authors())"`: Package authors. Supply a string for one author or an array for multiple. Like `user`, it takes its default value from the global Git config (`user.name` and `user.email`). ### Package Options - `host::AbstractString="github.com"`: URL to the code hosting service where packages will reside. - `dir::AbstractString="$(contractuser(Pkg.devdir()))"`: Directory to place packages in. -- `julia_version::VersionNumber=$(repr(DEFAULT_VERSION))`: Minimum allowed Julia version. +- `julia_version::VersionNumber=$(repr(default_version()))`: Minimum allowed Julia version. - `develop::Bool=true`: Whether or not to `develop` new packages in the active environment. ### Git Options @@ -39,13 +38,12 @@ Records common information used to generate a package. ### Template Plugins - `plugins::Vector{<:Plugin}=Plugin[]`: A list of [`Plugin`](@ref)s used by the template. -- `disabled_defaults::Vector{DataType}=DataType[]`: Default plugins to disable. +- `disable_defaults::Vector{DataType}=DataType[]`: Default plugins to disable. The default plugins are [`Readme`](@ref), [`License`](@ref), [`Tests`](@ref), and [`Gitignore`](@ref). To override a default plugin instead of disabling it altogether, supply it via `plugins`. ### Interactive Usage - `interactive::Bool=false`: When set, the template is created interactively, filling unset keywords with user input. -- `fast::Bool=false`: Skips prompts for any unsupplied keywords except `user` and `plugins`, accepting default values. """ struct Template authors::Vector{String} @@ -67,21 +65,19 @@ function Template(::Val{false}; kwargs...) user = getkw(kwargs, :user) isempty(user) && throw(ArgumentError("No user set, please pass user=username")) - host = getkw(kwargs, :host) - host = URI(occursin("://", host) ? host : "https://$host").host - authors = getkw(kwargs, :authors) authors isa Vector || (authors = map(strip, split(authors, ","))) + host = replace(getkw(kwargs, :host), r".*://" => "") + dir = abspath(expanduser(getkw(kwargs, :dir))) - disabled = getkw(kwargs, :disabled_defaults) - defaults = [Readme, License, Tests, Gitignore] - plugins = map(T -> T(), filter(T -> !(T in disabled), defaults)) - append!(plugins, getkw(kwargs, :plugins)) + disabled = getkw(kwargs, :disable_defaults) + enabled = filter(p -> !(typeof(p) in disabled), default_plugins()) + append!(enabled, getkw(kwargs, :plugins)) # This comprehension resolves duplicate plugin types by overwriting, # which means that default plugins get replaced by user values. - plugin_dict = Dict(typeof(p) => p for p in plugins) + plugins = Dict(typeof(p) => p for p in enabled) return Template( authors, @@ -91,7 +87,7 @@ function Template(::Val{false}; kwargs...) host, getkw(kwargs, :julia_version), getkw(kwargs, :manifest), - plugin_dict, + plugins, getkw(kwargs, :ssh), user, ) @@ -106,14 +102,14 @@ getkw(kwargs, k) = get(() -> defaultkw(k), kwargs, k) # Default Template keyword values. defaultkw(s::Symbol) = defaultkw(Val(s)) -defaultkw(::Val{:authors}) = DEFAULT_AUTHORS +defaultkw(::Val{:authors}) = default_authors() defaultkw(::Val{:develop}) = true defaultkw(::Val{:dir}) = Pkg.devdir() -defaultkw(::Val{:disabled_defaults}) = DataType[] +defaultkw(::Val{:disable_defaults}) = DataType[] defaultkw(::Val{:git}) = true defaultkw(::Val{:host}) = "github.com" -defaultkw(::Val{:julia_version}) = DEFAULT_VERSION +defaultkw(::Val{:julia_version}) = default_version() defaultkw(::Val{:manifest}) = false defaultkw(::Val{:plugins}) = Plugin[] defaultkw(::Val{:ssh}) = false -defaultkw(::Val{:user}) = DEFAULT_USER +defaultkw(::Val{:user}) = default_user() diff --git a/test/fixtures/Basic/.gitignore.txt b/test/fixtures/Basic/.gitignore.txt new file mode 100644 index 0000000..145cb1a --- /dev/null +++ b/test/fixtures/Basic/.gitignore.txt @@ -0,0 +1,3 @@ +.DS_Store +/Manifest.toml +/dev/ diff --git a/test/fixtures/Basic/LICENSE.txt b/test/fixtures/Basic/LICENSE.txt new file mode 100644 index 0000000..9ce1e63 --- /dev/null +++ b/test/fixtures/Basic/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2019 tester + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/test/fixtures/Basic/Manifest.toml.txt b/test/fixtures/Basic/Manifest.toml.txt new file mode 100644 index 0000000..f45eecf --- /dev/null +++ b/test/fixtures/Basic/Manifest.toml.txt @@ -0,0 +1,2 @@ +# This file is machine-generated - editing it directly is not advised + diff --git a/test/fixtures/Basic/Project.toml.txt b/test/fixtures/Basic/Project.toml.txt new file mode 100644 index 0000000..3d5ccb6 --- /dev/null +++ b/test/fixtures/Basic/Project.toml.txt @@ -0,0 +1,13 @@ +name = "Basic" +uuid = "5b7e9947-ddc0-4b3f-9b55-0d8042f74170" +authors = ["tester"] +version = "0.1.0" + +[compat] +julia = "1" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/test/fixtures/Basic/README.md.txt b/test/fixtures/Basic/README.md.txt new file mode 100644 index 0000000..0b51bff --- /dev/null +++ b/test/fixtures/Basic/README.md.txt @@ -0,0 +1 @@ +# Basic diff --git a/test/fixtures/Basic/src/Basic.jl.txt b/test/fixtures/Basic/src/Basic.jl.txt new file mode 100644 index 0000000..5c9a3d6 --- /dev/null +++ b/test/fixtures/Basic/src/Basic.jl.txt @@ -0,0 +1,5 @@ +module Basic + +greet() = print("Hello World!") + +end # module diff --git a/test/fixtures/Basic/test/runtests.jl.txt b/test/fixtures/Basic/test/runtests.jl.txt new file mode 100644 index 0000000..085a706 --- /dev/null +++ b/test/fixtures/Basic/test/runtests.jl.txt @@ -0,0 +1,6 @@ +using Basic +using Test + +@testset "Basic.jl" begin + # Write your tests here. +end diff --git a/test/generate.jl b/test/generate.jl new file mode 100644 index 0000000..58fb980 --- /dev/null +++ b/test/generate.jl @@ -0,0 +1,25 @@ +default_files(pkg::AbstractString) = [ + ".gitignore", + "LICENSE", + "Manifest.toml", + "Project.toml", + "README.md", + "src/$pkg.jl", + "test/runtests.jl", +] + +function reference_test(pkg_dir::AbstractString, path::AbstractString) + pkg = basename(pkg_dir) + path = replace(path, "/" => path_separator) + # All fixture files are .txt because otherwise ReferenceTests/FileIO can't handle them. + reference = joinpath(@__DIR__, "fixtures", pkg, path * ".txt") + observed = read(joinpath(pkg_dir, path), String) + @test_reference reference observed +end + +@testset "Default package" begin + pkg = "Basic" + t = tpl(; develop=false, authors=USER) + t(pkg) + foreach(f -> reference_test(joinpath(t.dir, pkg), f), default_files(pkg)) +end diff --git a/test/runtests.jl b/test/runtests.jl index e69de29..f023f0d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -0,0 +1,32 @@ +using Base.Filesystem: path_separator + +using Pkg: Pkg +using Random: Random +using Test: @test, @testset, @test_throws + +using ReferenceTests: @test_reference + +using PkgTemplates +const PT = PkgTemplates + +const PKG = "TestPkg" +const USER = "tester" + +Random.seed!(1) + +tpl(; kwargs...) = Template(; user=USER, kwargs...) + +@testset "PkgTemplates.jl" begin + mktempdir() do dir + Pkg.activate(dir) + pushfirst!(DEPOT_PATH, dir) + try + include("template.jl") + include("generate.jl") + # include("plugin.jl") + # include("interactive.jl") + finally + popfirst!(DEPOT_PATH) + end + end +end diff --git a/test/template.jl b/test/template.jl new file mode 100644 index 0000000..95ffa55 --- /dev/null +++ b/test/template.jl @@ -0,0 +1,52 @@ +@testset "Template constructor" begin + @testset "user" begin + if isempty(PT.default_user()) + @test_throws ArgumentError Template() + haskey(ENV, "CI") && run(`git config --global github.user $USER`) + end + @test Template().user == PT.default_user() + end + + @testset "authors" begin + @test tpl(; authors=["a"]).authors == ["a"] + @test tpl(; authors="a").authors == ["a"] + @test tpl(; authors="a,b").authors == ["a", "b"] + @test tpl(; authors="a, b").authors == ["a", "b"] + end + + @testset "host" begin + @test tpl(; host="https://foo.com").host == "foo.com" + end + + @testset "dir" begin + @test tpl(; dir="/foo/bar").dir == "/foo/bar" + @test tpl(; dir="foo").dir == abspath("foo") + @test tpl(; dir="~/foo").dir == abspath(expanduser("~/foo")) + end + + @testset "plugins / disabled_defaults" begin + function test_plugins(plugins, expected, disabled=DataType[]) + t = tpl(; plugins=plugins, disable_defaults=disabled) + @test issetequal(values(t.plugins), expected) + end + + defaults = PT.default_plugins() + test_plugins([], defaults) + test_plugins([Citation()], union(defaults, [Citation()])) + # Overriding a default plugin. + gi = Gitignore(; dev=false) + test_plugins([gi], union(setdiff(defaults, [Gitignore()]), [gi])) + # Disabling a default plugin. + test_plugins([], setdiff(defaults, [Gitignore()]), [Gitignore]) + end +end + +@testset "hasplugin" begin + t = tpl(; plugins=[Documenter{TravisCI}()]) + @test PT.hasplugin(t, typeof(first(PT.default_plugins()))) + @test PT.hasplugin(t, Documenter) + @test PT.hasplugin(t, _ -> true) + @test !PT.hasplugin(t, _ -> false) + @test !PT.hasplugin(t, Citation) + @test !PT.hasplugin(t, PT.is_ci) +end