From 0f2e22bbae24d0d7dce350c985720e108acac884 Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:54:46 +0200 Subject: [PATCH] Set up Literate with Documenter --- .github/workflows/DocPreviewCleanup.yml | 28 +++++ .gitignore | 2 + Project.toml | 4 +- README.md | 94 +-------------- docs/Manifest.toml | 147 +++++++++++++++++++++--- docs/Project.toml | 1 + docs/make.jl | 23 +++- docs/src/animals.md | 105 +++++++++++++++++ docs/src/api.md | 12 ++ docs/src/index.md | 14 --- src/Interfaces.jl | 2 + test/animals.jl | 101 ++++++++++++++++ test/runtests.jl | 62 ++-------- 13 files changed, 420 insertions(+), 175 deletions(-) create mode 100644 .github/workflows/DocPreviewCleanup.yml create mode 100644 docs/src/animals.md create mode 100644 docs/src/api.md delete mode 100644 docs/src/index.md create mode 100644 test/animals.jl diff --git a/.github/workflows/DocPreviewCleanup.yml b/.github/workflows/DocPreviewCleanup.yml new file mode 100644 index 0000000..365d56f --- /dev/null +++ b/.github/workflows/DocPreviewCleanup.yml @@ -0,0 +1,28 @@ +name: Doc Preview Cleanup + +on: + pull_request: + types: [closed] + +jobs: + doc-preview-cleanup: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout gh-pages branch + uses: actions/checkout@v3 + with: + ref: gh-pages + - name: Delete preview and history + push changes + run: | + if [ -d "previews/PR$PRNUM" ]; then + git config user.name "Documenter.jl" + git config user.email "documenter@juliadocs.github.io" + git rm -rf "previews/PR$PRNUM" + git commit -m "delete preview" + git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree}) + git push --force origin gh-pages-new:gh-pages + fi + env: + PRNUM: ${{ github.event.number }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 20fe29d..77d3e64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ +.vscode *.jl.*.cov *.jl.cov *.jl.mem /Manifest.toml /docs/build/ +/docs/src/index.md \ No newline at end of file diff --git a/Project.toml b/Project.toml index 53e524a..b257b01 100644 --- a/Project.toml +++ b/Project.toml @@ -7,7 +7,9 @@ version = "0.1.0" julia = "1.6" [extras] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test"] +test = ["Aqua", "Documenter", "Test"] diff --git a/README.md b/README.md index 82841ef..8ecd352 100644 --- a/README.md +++ b/README.md @@ -17,100 +17,10 @@ specifically: - Tests: `@implements` declarations should be tested in package tests. - Docs: interface documentation can be inserted into trait documentation. -__Note: the syntax here is likely to change over 2022 as we work out the best ways to define interfaces__ - -## Example - -See the `IterationInterface` in BaseInterfaces.jl (a subpackage of this package) +See the `IterationInterface` in BaseInterfaces.jl (a subpackage of this package) or the documentation for examples of `@interface` and `@implements`. -But heres an examples using Animals, and the implementation of a Duck. - -First we define the interface methods, and a list of mandatory and -optional properties of the interface, with conditions, using the `@interface` -macro. - -The `@interface` macro takes two argumens -1. The name of the interface, which should usully end with "Interface" -2. The `mandatory` and `optional` components of the interface written as a `NamedTuple`, - with functions or tuple of functions that test them. - -```julia -module Animals - -using Interfaces - -# Define the methods the interface uses -function age end -function walk end -function talk end -function dig end - -# Define the interface conditions -@interface AnimalInterface ( - mandatory = (; - age = ( - x -> age(x) isa Real, - x -> age(x) >= 0, - ) - ), - optional = (; - walk = x -> walk(x) isa String, - talk = x -> talk(x) isa Symbol, - dig = x -> dig(x) isa String, - ), -) - -end -``` - -Now we can implement the AnimalInterface, for a Duck. - -The `@implements` macro takes two arguments. -1. The interface type, with a tuple of optional components in - its first type parameter. -2. The type for which the interface is implemented. - -```julia -using Interfaces - -# Define our Duck object -struct Duck - age::Int -end - -# And extend Animals methods for it -Animals.age(duck::Duck) = duck.age -Animals.walk(::Duck) = "waddle" -Animals.talk(::Duck) = :quack - -# And define the interface -@implements Animals.AnimalInterface{(:walk, :talk)} Duck -``` - -Now we have some methods we can use as traits, and test the interface with: - -```julia -julia> Interfaces.implements(Animals.AnimalInterface{:walk}, Duck) -true - -julia> Interfaces.implements(Animals.AnimalInterface{:dig}, Duck) -false - -# We can test the interface -julia> Interfaces.test(Animals.AnimalInterface, Duck, [Duck(1), Duck(2)]) -true - -# Or components of it: -julia> Interfaces.test(Animals.AnimalInterface{(:walk,:talk)}, Duck, [Duck(1), Duck(2)]) -true - -# Test another type -struct Chicken end - -julia> Interfaces.implements(Animals.AnimalInterface, Chicken) -false -``` +__Note: the syntax here is likely to change as we work out the best ways to define interfaces__ If you think it should behave differently or there is better syntax, please make an issue. diff --git a/docs/Manifest.toml b/docs/Manifest.toml index b041896..cb4307f 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -1,13 +1,26 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.7.0" +julia_version = "1.10.0-beta2" manifest_format = "2.0" +project_hash = "f02347b00ee559bf1c602a5e40edf44579c536cb" [[deps.ANSIColoredPrinters]] git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" version = "0.0.1" +[[deps.AbstractTrees]] +git-tree-sha1 = "faa260e4cb5aba097a73fab382dd4b5819d8ec8c" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.4.4" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -17,21 +30,29 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[deps.DocStringExtensions]] deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" +version = "0.9.3" [[deps.Documenter]] -deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "3eb46f2549b52a79206469cdc03ae2518ded8d31" +deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "Dates", "DocStringExtensions", "Downloads", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "Test", "Unicode"] +git-tree-sha1 = "f667b805e90d643aeb1ca70189827f991a7cc115" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.18" +version = "1.1.0" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" [[deps.IOCapture]] deps = ["Logging", "Random"] -git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" +git-tree-sha1 = "d75853a0bdbfb1ac815478bacd89cd27b550ace6" uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.2" +version = "0.2.3" [[deps.InteractiveUtils]] deps = ["Markdown"] @@ -44,14 +65,43 @@ version = "0.1.0" [[deps.JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e" +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.3" +version = "0.21.4" + +[[deps.LazilyInitializedFields]] +git-tree-sha1 = "410fe4739a4b092f2ffe36fcb0dcc3ab12648ce1" +uuid = "0e77f7df-68c5-4e49-93ce-4cd80f5598bf" +version = "1.2.1" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.0.1+1" [[deps.LibGit2]] deps = ["Base64", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Literate]] +deps = ["Base64", "IOCapture", "JSON", "REPL"] +git-tree-sha1 = "ae5703dde29228490f03cbd64c47be8131819485" +uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +version = "2.15.0" + [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" @@ -59,17 +109,50 @@ uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +[[deps.MarkdownAST]] +deps = ["AbstractTrees", "Markdown"] +git-tree-sha1 = "e8513266815200c0c8f522d6d44ffb5e9b366ae4" +uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" +version = "0.1.1" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + [[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" [[deps.Parsers]] -deps = ["Dates"] -git-tree-sha1 = "1285416549ccfcdf0c50d4997a94331e88d68413" +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "716e24b21538abc91f6205fd1d8363f39b442851" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.3.1" +version = "2.7.2" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "03b4c25b43cb84cee5c90aa9b5ea0a78fd848d2f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.0" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "00805cd429dcb4870060ff49ef443486c262e38e" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.1" [[deps.Printf]] deps = ["Unicode"] @@ -80,11 +163,18 @@ deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[deps.Random]] -deps = ["SHA", "Serialization"] +deps = ["SHA"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +[[deps.RegistryInstances]] +deps = ["LazilyInitializedFields", "Pkg", "TOML", "Tar"] +git-tree-sha1 = "ffd19052caf598b8653b99404058fce14828be51" +uuid = "2792f1a3-b283-48e8-9a74-f99dce5104f3" +version = "0.1.0" + [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" @@ -92,9 +182,38 @@ uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + [[deps.Test]] deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + [[deps.Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" diff --git a/docs/Project.toml b/docs/Project.toml index ba162d1..b95a17c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,3 +1,4 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Interfaces = "85a1e053-f937-4924-92a5-1367d23b7b87" +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" diff --git a/docs/make.jl b/docs/make.jl index 3a86881..ff699df 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,14 +1,28 @@ -using Interfaces using Documenter +using Interfaces +using Literate DocMeta.setdocmeta!(Interfaces, :DocTestSetup, :(using Interfaces); recursive=true) +# Copy README +cp( + joinpath(dirname(@__DIR__), "README.md"), + joinpath(@__DIR__, "src", "index.md"), + force=true, +) + +# Copy test files +Literate.markdown( + joinpath(dirname(@__DIR__), "test", "animals.jl"), + joinpath(@__DIR__, "src") +) + makedocs(; modules=[Interfaces], authors="Rafael Schouten <rafaelschouten@gmail.com>", - repo="https://github.com/rafaqz/Interfaces.jl/blob/{commit}{path}#{line}", sitename="Interfaces.jl", format=Documenter.HTML(; + repolink="https://github.com/rafaqz/Interfaces.jl", prettyurls=get(ENV, "CI", "false") == "true", canonical="https://rafaqz.github.io/Interfaces.jl", edit_link="main", @@ -16,10 +30,15 @@ makedocs(; ), pages=[ "Home" => "index.md", + "API reference" => "api.md", + "Examples" => [ + "Single argument" => "animals.md", + ] ], ) deploydocs(; repo="github.com/rafaqz/Interfaces.jl", devbranch="main", + push_preview=true, ) diff --git a/docs/src/animals.md b/docs/src/animals.md new file mode 100644 index 0000000..9f2d9ac --- /dev/null +++ b/docs/src/animals.md @@ -0,0 +1,105 @@ +```@meta +EditURL = "../../test/animals.jl" +``` + +# Single-argument interface + +Here's an examples using animals, and the implementation of a duck. + +## Definition + +First we define the interface methods, and a list of mandatory and +optional properties of the interface, with conditions, using the `@interface` +macro. + +The `@interface` macro takes three arguments: +1. The name of the interface, which should usully end with "Interface" +2. The `mandatory` and `optional` components of the interface written as a `NamedTuple`, with functions or tuple of functions that test them. +3. The interface docstring (the interface is represented as a type) + +````@example animals +module Animals + +using Interfaces + +function age end +function walk end +function talk end +function dig end + +@interface AnimalInterface ( + mandatory = ( + age = ( + "all animals have a `Real` age" => x -> age(x) isa Real, + "all animals have an age larger than zero" => x -> age(x) >= 0, + ), + ), + optional = ( + walk = "this animal can walk" => x -> walk(x) isa String, + talk = "this animal can talk" => x -> talk(x) isa Symbol, + dig = "this animal can dig" => x -> dig(x) isa String, + ) +) """ +Defines a generic interface for animals to do the things they do best. +""" + +end; +nothing #hide +```` + +## Implementation + +````@example animals +using Interfaces +```` + +Now we implement the `AnimalInterface`, for a `Duck`. + +````@example animals +struct Duck + age::Int +end + +Animals.age(duck::Duck) = duck.age +Animals.walk(::Duck) = "waddle" +Animals.talk(::Duck) = :quack +```` + +We then test that the interface is correctly implemented + +````@example animals +ducks = [Duck(1), Duck(2)] +Interfaces.test(Animals.AnimalInterface, Duck, ducks) +```` + +Finally we declare it, so that the information can be used in static dispatch. + +The `@implements` macro takes two arguments. +1. The interface type, with a tuple of optional components in its first type parameter. +2. The type for which the interface is implemented. + +````@example animals +@implements Animals.AnimalInterface{(:walk,:talk)} Duck +```` + +Now let's see what happens when the interface is not correctly implemented. + +````@example animals +struct Chicken end +```` + +As expected, the tests fail + +````@example animals +chickens = [Chicken()] +try + Interfaces.test(Animals.AnimalInterface, Chicken, chickens) +catch e + print(e) +end +```` + +--- + +*This page was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).* + diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..b617e75 --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,12 @@ +# API reference + +## Docstrings + +```@autodocs +Modules = [Interfaces] +``` + +## Index + +```@index +``` diff --git a/docs/src/index.md b/docs/src/index.md deleted file mode 100644 index f85e27f..0000000 --- a/docs/src/index.md +++ /dev/null @@ -1,14 +0,0 @@ -```@meta -CurrentModule = Interfaces -``` - -# Interfaces - -Documentation for [Interfaces](https://github.com/rafaqz/Interfaces.jl). - -```@index -``` - -```@autodocs -Modules = [Interfaces] -``` diff --git a/src/Interfaces.jl b/src/Interfaces.jl index e1ef015..00fedd8 100644 --- a/src/Interfaces.jl +++ b/src/Interfaces.jl @@ -1,5 +1,7 @@ module Interfaces +@doc read(joinpath(dirname(@__DIR__), "README.md"), String) Interfaces + export @implements, @interface include("interface.jl") diff --git a/test/animals.jl b/test/animals.jl new file mode 100644 index 0000000..868f8c3 --- /dev/null +++ b/test/animals.jl @@ -0,0 +1,101 @@ +# # Single-argument interface + +# Here's an examples using animals, and the implementation of a duck. + +# ## Definition + +#= +First we define the interface methods, and a list of mandatory and +optional properties of the interface, with conditions, using the `@interface` +macro. + +The `@interface` macro takes three arguments: +1. The name of the interface, which should usully end with "Interface" +2. The `mandatory` and `optional` components of the interface written as a `NamedTuple`, with functions or tuple of functions that test them. +3. The interface docstring (the interface is represented as a type) +=# + +module Animals + +using Interfaces + +function age end +function walk end +function talk end +function dig end + +@interface AnimalInterface ( + mandatory = ( + age = ( + "all animals have a `Real` age" => x -> age(x) isa Real, + "all animals have an age larger than zero" => x -> age(x) >= 0, + ), + ), + optional = ( + walk = "this animal can walk" => x -> walk(x) isa String, + talk = "this animal can talk" => x -> talk(x) isa Symbol, + dig = "this animal can dig" => x -> dig(x) isa String, + ) +) """ +Defines a generic interface for animals to do the things they do best. +""" + +end; + +# ## Implementation + +using Interfaces + +# Now we implement the `AnimalInterface`, for a `Duck`. + +struct Duck + age::Int +end + +Animals.age(duck::Duck) = duck.age +Animals.walk(::Duck) = "waddle" +Animals.talk(::Duck) = :quack + +# We then test that the interface is correctly implemented + +ducks = [Duck(1), Duck(2)] +Interfaces.test(Animals.AnimalInterface, Duck, ducks) + +#= +Finally we declare it, so that the information can be used in static dispatch. + +The `@implements` macro takes two arguments. +1. The interface type, with a tuple of optional components in its first type parameter. +2. The type for which the interface is implemented. +=# + +@implements Animals.AnimalInterface{(:walk,:talk)} Duck + +# Now let's see what happens when the interface is not correctly implemented. +struct Chicken end + +# As expected, the tests fail +chickens = [Chicken()] +try + Interfaces.test(Animals.AnimalInterface, Chicken, chickens) +catch e + print(e) +end + +# The following tests are not included in the docs #src + +using Test #src + +@testset "Duck" begin #src + @test Interfaces.implements(Animals.AnimalInterface, Duck) == true #src + @test Interfaces.implements(Animals.AnimalInterface{:dig}, Duck) == false #src + @test Interfaces.test(Animals.AnimalInterface, Duck, ducks) == true #src + @test Interfaces.test(Animals.AnimalInterface{(:walk,:talk)}, Duck, ducks) == true #src + # TODO wrap errors somehow, or just let Invariants.jl handle that. #src + @test_throws MethodError Interfaces.test(Animals.AnimalInterface{:dig}, Duck, ducks) #src +end #src + +@testset "Chicken" begin #src + @test Interfaces.implements(Animals.AnimalInterface{(:walk,:talk)}, Chicken()) == false #src + @test_throws MethodError Interfaces.test(Animals.AnimalInterface{(:walk,:talk)}, Chicken()) #src +end #src diff --git a/test/runtests.jl b/test/runtests.jl index 8c3c9da..943b02d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,56 +1,14 @@ +using Aqua +using Documenter using Interfaces using Test -module Animals - -using Interfaces - -function age end -function walk end -function talk end -function dig end - -@interface AnimalInterface ( - mandatory = ( - age = ( - "all animals have a `Real` age" => x -> age(x) isa Real, - "all animals have an age larger than zero" => x -> age(x) >= 0, - ), - ), - optional = ( - walk = "this animal can walk" => x -> walk(x) isa String, - talk = "this animal can talk" => x -> talk(x) isa Symbol, - dig = "this animal can dig" => x -> dig(x) isa String, - ) -) """ -Defines a generic interface for animals to do the things they do best. -""" - -end - -struct Duck - age::Int -end - -Animals.age(duck::Duck) = duck.age -Animals.walk(::Duck) = "waddle" -Animals.talk(::Duck) = :quack - -@implements dev Animals.AnimalInterface{(:walk,:talk)} Duck - -@testset "duck" begin - ducks = [Duck(1), Duck(2)] - @test Interfaces.implements(Animals.AnimalInterface, Duck) == true - @test Interfaces.implements(Animals.AnimalInterface{:dig}, Duck) == false - @test Interfaces.test(Animals.AnimalInterface, Duck, ducks) == true - @test Interfaces.test(Animals.AnimalInterface{(:walk,:talk)}, Duck, ducks) == true - # TODO wrap errors somehow, or just let Invariants.jl handle that. - @test_throws MethodError Interfaces.test(Animals.AnimalInterface{:dig}, Duck, ducks) -end - -struct Chicken end - -@testset "chicken" begin - @test Interfaces.implements(Animals.AnimalInterface{(:walk,:talk)}, Chicken()) == false - @test_throws MethodError Interfaces.test(Animals.AnimalInterface{(:walk,:talk)}, Chicken()) +@testset verbose = true "Interfaces.jl" begin + doctest(Interfaces) + @testset "Aqua" begin + Aqua.test_all(Interfaces) + end + @testset "Animals" begin + include("animals.jl") + end end