Packages
credo
1.3.1
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.7-rc.0
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.2-rc.4
1.7.2-rc.3
1.7.2-rc.2
1.7.2-rc.1
1.7.2-rc.0
1.7.1
1.7.0
1.7.0-rc.2
1.7.0-rc.1
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.4.1
1.4.0
1.4.0-rc.2
1.4.0-rc.1
1.3.2
1.3.1
1.3.0
1.3.0-rc3
1.3.0-rc2
1.3.0-rc1
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc4
1.2.0-rc3
1.2.0-rc2
1.2.0-rc1
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.1.0-rc3
1.1.0-rc2
1.1.0-rc1
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.1-rc1
1.0.0
1.0.0-rc1
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.9.0-rc8
0.9.0-rc7
0.9.0-rc6
0.9.0-rc5
0.9.0-rc4
0.9.0-rc3
0.9.0-rc2
0.9.0-rc1
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.8.0-rc7
0.8.0-rc6
0.8.0-rc5
0.8.0-rc4
0.8.0-rc3
0.8.0-rc2
0.8.0-rc1
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.6.0-rc2
0.6.0-rc1
0.5.3
0.5.2
0.5.1
0.5.0
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.10-dev
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.4.0-beta5
0.4.0-beta4
0.4.0-beta3
0.4.0-beta2
0.4.0-beta1
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.3.0-dev2
0.3.0-dev
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.0.1-dev
A static code analysis tool with a focus on code consistency and teaching.
Current section
Files
Jump to
Current section
Files
lib/credo/test/case.ex
defmodule Credo.Test.Case do
@moduledoc """
Conveniences for testing Credo custom checks and plugins.
This module can be used in your test cases, like this:
use Credo.Test.Case
Using this module will:
* import all the functions from this module
* make the test case `:async` by default (use `use Credo.Test.Case, async: false` to opt out)
## Testing custom checks
Suppose we have a custom check in our project that checks whether or not
the "FooBar rules" are applied (one of those *very* project-specific things).
defmodule MyProject.MyCustomChecks.FooBar do
use Credo.Check, category: :warning, base_priority: :high
def run(source_file, params) do
# ... implement all the "FooBar rules" ...
end
end
When we want to test this check, we can use `Credo.Test.Case` for convenience:
defmodule MyProject.MyCustomChecks.FooBarTest do
use Credo.Test.Case
alias MyProject.MyCustomChecks.FooBar
test "it should NOT report expected code" do
\"\"\"
defmodule CredoSampleModule do
# ... some good Elixir code ...
end
\"\"\"
|> to_source_file()
|> run_check(FooBar)
|> refute_issues()
end
test "it should report code that violates the FooBar rule" do
\"\"\"
defmodule CredoSampleModule do
# ... some Elixir code that violates the FooBar rule ...
end
\"\"\"
|> to_source_file()
|> run_check(FooBar)
|> assert_issues()
end
end
This is as simple and mundane as it looks (which is a good thing):
We have two tests: one for the good case, one for the bad case.
In each, we create a source file representation from a heredoc, run our custom check and assert/refute the issues
we expect.
## Asserting found issues
Once we get to know domain a little better, we can add more tests, typically testing for other bad cases in which
our check should produce issues.
Note that there are two assertion functions for this: `assert_issue/2` and `assert_issues/2`, where the first one
ensures that there is a single issue and the second asserts that there are at least two issues.
Both functions take an optional `callback` as their second parameter, which is called with the `issue` or the
list of `issues` found, which makes it convenient to check for the issues properties ...
\"\"\"
# ... any Elixir code ...
\"\"\"
|> to_source_file()
|> run_check(FooBar)
|> assert_issue(fn issue -> assert issue.trigger == "foo" end)
... or properties of the list of issues:
\"\"\"
# ... any Elixir code ...
\"\"\"
|> to_source_file()
|> run_check(FooBar)
|> assert_issue(fn issues -> assert Enum.count(issues) == 3 end)
## Testing checks that analyse multiple source files
For checks that analyse multiple source files, like Credo's consistency checks, we can use `to_source_files/1` to
create
[
\"\"\"
# source file 1
\"\"\",
\"\"\"
# source file 2
\"\"\"
]
|> to_source_files()
|> run_check(FooBar)
|> refute_issues()
If our check needs named source files, we can always use `to_source_file/2` to create individually named source
files and combine them into a list:
source_file1 =
\"\"\"
# source file 1
\"\"\"
|> to_source_file("foo.ex")
source_file2 =
\"\"\"
# source file 2
\"\"\"
|> to_source_file("bar.ex")
[source_file1, source_file2]
|> run_check(FooBar)
|> assert_issue(fn issue -> assert issue.filename == "foo.ex" end)
"""
defmacro __using__(opts) do
async = opts[:async] != false
quote do
use ExUnit.Case, async: unquote(async)
import Credo.Test.Case
end
end
alias Credo.Test.CheckRunner
alias Credo.Test.SourceFiles
alias Credo.Test.Assertions
@doc """
Refutes the presence of any issues.
"""
def refute_issues(issues) do
Assertions.refute_issues(issues)
end
@doc """
Asserts the presence of a single issue.
"""
def assert_issue(issues, callback \\ nil) do
Assertions.assert_issue(issues, callback)
end
@doc """
Asserts the presence of more than one issue.
"""
def assert_issues(issues, callback \\ nil) do
Assertions.assert_issues(issues, callback)
end
@doc false
# TODO: remove this
def assert_trigger(issue, trigger) do
Assertions.assert_trigger(issue, trigger)
end
#
@doc """
Runs the given `check` on the given `source_file` using the given `params`.
"x = 5"
|> to_source_file()
|> run_check(MyProject.MyCheck, foo_parameter: "bar")
"""
def run_check(source_file, check, params \\ []) do
CheckRunner.run_check(source_file, check, params)
end
#
@doc """
Converts the given `source` string to a `%SourceFile{}`.
"x = 5"
|> to_source_file()
"""
def to_source_file(source) do
SourceFiles.to_source_file(source)
end
@doc """
Converts the given `source` string to a `%SourceFile{}` with the given `filename`.
"x = 5"
|> to_source_file("simple.ex")
"""
def to_source_file(source, filename) do
SourceFiles.to_source_file(source, filename)
end
@doc """
Converts the given `list` of source code strings to a list of `%SourceFile{}` structs.
["x = 5", "y = 6"]
|> to_source_files()
"""
def to_source_files(list) do
Enum.map(list, &to_source_file/1)
end
end