-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 801a60a
Showing
16 changed files
with
1,569 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
local expect = require('expect') | ||
local busted = require('busted') | ||
expect.parameters.throw = busted.fail | ||
|
||
return { | ||
default = { | ||
['auto-insulate'] = false, | ||
lpath = './?.lua;' .. (require('lfs').currentdir()) .. '/?.lua;' | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
name: ci | ||
|
||
on: | ||
pull_request: | ||
push: | ||
branches: master | ||
|
||
jobs: | ||
build: | ||
name: Build and test | ||
|
||
strategy: | ||
matrix: | ||
lua-version: ["5.4", "5.3", "5.2", "5.1", "luajit"] | ||
os: ["ubuntu-latest"] | ||
include: | ||
- os: "macos-latest" | ||
lua-version: "5.4" | ||
- os: "windows-latest" | ||
lua-version: "luajit" | ||
runs-on: ${{ matrix.os }} | ||
|
||
steps: | ||
- uses: actions/checkout@master | ||
|
||
- uses: leafo/gh-actions-lua@master | ||
with: | ||
luaVersion: ${{ matrix.lua-version }} | ||
|
||
- uses: hishamhm/gh-actions-luarocks@master | ||
|
||
- name: Build | ||
run: | | ||
luarocks make --only-deps | ||
- name: Test | ||
run: | | ||
luarocks lint expect-dev-1.rockspec | ||
luarocks test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.src.rock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
MIT License | ||
|
||
Copyright (c) 2022 Stéphane Veyret | ||
|
||
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 (including the next | ||
paragraph) 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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Expect - BDD expect notation for LUA tests | ||
|
||
Widely inspired by `chaijs`, `expect` aims to bring the behavior-driven development “expect” notation to LUA tests. | ||
|
||
```lua | ||
expect(2 + 2).to.be.a('number').And.to.equal(4).but.Not.to.be.Nil() | ||
``` | ||
|
||
# Installation | ||
|
||
You can install `expect` using LuaRocks with the command: | ||
|
||
```shell | ||
luarocks install expect | ||
``` | ||
|
||
# Usage | ||
|
||
In order to use `expect` in your tests, look at the [usage manual](doc/usage.md). | ||
|
||
If you want to write a new plugin, look at the [plugin manual](doc/plugin.md). | ||
|
||
# Credits | ||
|
||
Some parts of this projects are inspired/copied from: | ||
|
||
- The NodeJS `chaijs` project: https://github.com/chaijs/chai | ||
- The LUA `luassert` project: https://github.com/lunarmodules/luassert |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
It is rather easy to write plugins in order to extend the capabilities of `expect`. Anyway, `expect` will | ||
prevent from adding the same feature several times, so plugin writers must carefully choose the name of the | ||
features. Remember that features are case-insensitive, so you cannot add an `equal` feature, neither can you | ||
add an `Equal` one. | ||
|
||
# Example | ||
|
||
The [core.lua](../expect/core.lua) file itself is a plugin containing the core features. You can use it as an | ||
example to see how a plugin should be written. | ||
|
||
# Basic | ||
|
||
Your plugin should return a function taking `expect` as a single parameter. The function will add the | ||
features (assertions) to `expect`. You can add diffent kinds of features: | ||
|
||
- properties, using `expect.addProperty(name[, fun])`, will add a feature callable as a property; you may do | ||
assertions in it, but remember that it is an error to terminate a statement with a property in LUA, so it is | ||
better to either do nothing (chainable word) or set a control data property; | ||
- methods, using `expect.addMethod(name[, fun])`, will add a feature callable as a method, which may take | ||
some parameters; | ||
- mixed, using `expect.addChainableMethod(name[, fun[, fun]])`, will add a feature callable both as a method | ||
(first provided callback) and as a property (second callback); both calls can have an action, but beware that | ||
the action executed for the property usage is also executed when the feature is called as a method. | ||
|
||
If you don’t provide callbacks when using these functions, a no-op one will be used. | ||
|
||
```lua | ||
local FailureMessage = require('expect.FailureMessage') | ||
|
||
return function(expect) | ||
-- Add a no-op property (chaining word) | ||
expect.addProperty('whatever') | ||
|
||
-- Add a property setting a flag on control data | ||
expect.addProperty('fluffy', function(controlData) | ||
controlData.fluffy = true | ||
end) | ||
|
||
-- Add a method with a size parameter | ||
expect.addMethod('longerThan', function(controlData, size) | ||
controlData:checkType("string") -- Only applies to strings | ||
if controlData.fluffy then -- See if this flag was previously set | ||
size = size * 2 | ||
end | ||
local params = { -- Prepare parameters for failure messages | ||
size = size | ||
} | ||
controlData:assert(controlData.actual:len() > size, FailureMessage('expected {#} to be longer than {size}', params), | ||
FailureMessage('expected {#} to not be longer than {size}', params)) | ||
end) | ||
|
||
-- Add a mixed feature | ||
expect.addChainableMethod('theAnswerToLifeUniverseAndEverything', function(controlData) | ||
controlData:assert(controlData.actual == 42, FailureMessage('expected {#} to be 42'), | ||
FailureMessage('expected {#} to not be 42')) | ||
end, function(controlData) | ||
controlData.answer = 42 | ||
end) | ||
end | ||
``` | ||
|
||
All this may be used this way: | ||
|
||
```lua | ||
expect("a long string").to.be.fluffy.And.theAnswerToLifeUniverseAndEverything.but.longerThan(3) | ||
expect(42).to.whatever.be.theAnswerToLifeUniverseAndEverything() | ||
``` | ||
|
||
# API | ||
|
||
## ControlData | ||
|
||
The first parameter provided to a feature function is a `ControlData` object. This object can contain any | ||
data needed for the assertion. The object is shallow-copied between each chained feature. If you add your own | ||
property to this object, be careful to choose the name in order to prevent conflicts with other plugins. | ||
|
||
To create a `ControlData` object, simply call `ControlData(data)` where `data` is either a table or a | ||
`ControlData` object which will be shallow-copied. But you probably do not need to directly create a | ||
`ControlData` object, this kind of object is usually created through the `Expect` object. | ||
|
||
Not counting plugin additions, the `ControlData` object contains the following properties and functions: | ||
|
||
### actual | ||
|
||
This is the actual object being tested. Usually, this is the one provided to the `expect` function as first | ||
parameter, but this can be modified by a feature. | ||
|
||
### negate | ||
|
||
This property is set to true if the user called the `not` feature earlier in the assertion. It can be either | ||
`nil` or `false` otherwise. | ||
|
||
### checkType(expected[, checkNegation]) | ||
|
||
You may call this function to ensure that actual object is of appropriate type. If `checkNegation` is `true`, | ||
then the check will be inverted if the assertion is negated. The function does not return any value but fails | ||
if the type is not of expected type. | ||
|
||
### checkIfCallable([checkNegation]) | ||
|
||
This function can be used to ensure that the actual object is callable, i.e. either a function or a table | ||
with a metatable defining a `__call` function. If `checkNegation` is `true`, then the check will be inverted | ||
if the assertion is negated. The function does not return any value but fails if the actual object is not | ||
callable. | ||
|
||
### assert(expr, positiveMsg[, negativeMsg[, level]]) | ||
|
||
Call this function to process your assertion. If a `negativeMsg` is provided (not `nil`), then the function | ||
will check if the assertion is negated and invert its behavior accordingly. Otherwise, the function fails if | ||
`expr` is false. | ||
|
||
- `positiveMsg` is the message to display (`FailureMessage`) if `expr` is false and the assertion is not | ||
inverted; | ||
- `negativeMsg` is the message to display (`FailureMessage`) if `expr` is true and the assertion is inverted; | ||
- `level` is a the level of functions to be ignored when throwing the error in order to show the real source | ||
of the error; you usually should not need to set it. | ||
|
||
### fail(message[, level]) | ||
|
||
This function make the assertion fail immediately, displaying the provided `message` (`FailureMessage`). The | ||
`level` parameter is the level of functions to be ignored when throwing the error in order to show the real | ||
source of the error; you usually should not need to set it. | ||
|
||
## Expect | ||
|
||
The `Expect` object is the one created by the `expect()` function and all consecutive features called. This | ||
object does not contain any accessible data by itself, but it creates the `ControlData` object used when | ||
calling the features, and it redirects every property request to the appropriate feature. | ||
|
||
An `Expect` object can be created by calling `Expect(data)`, where `data` is given to `ControlData` | ||
constructor. | ||
|
||
## FailureMessage | ||
|
||
A `FailureMessage` object is used to provide a message composed of a pattern and parameters. The message will | ||
only be constructed before being used, which prevent loosing time creating an unneeded string. Parameters may | ||
be formatted, depending on the pattern, in order to be clearly readable by the end-user. | ||
|
||
To create a `FailureMessage` object, call `FailureMessage(pattern, parameters)` where `pattern` is the | ||
pattern and `parameters` is a table containing the parameters: keys are the parameter names and values are | ||
the values to show to end user. If a parameter is referenced in the pattern but is not in the `parameters` | ||
table it will not be considered empty but `nil` (displayed as `(nil)`). | ||
|
||
The pattern is a string containing placeholders for the parameters in the format `{name}` where `name` is the | ||
name of the parameter. This name should only be made of letters, bad things may happen otherwise. | ||
|
||
You do not need to provide `actual` to the parameters, it will be automatically added and can be displayed in | ||
the message using the placeholder `{#}`. | ||
|
||
If you want to add content without formatting, you can add use the format `{!name}` for the placeholder. The | ||
parameter `name` will then be displayed using a simple `tostring` and no complex formatting. | ||
|
||
Your pattern must not contain opening curly brace `{` except to indicate the start of a placeholder. If you | ||
need to display an opening curly brace, add an empty placeholder `{}`. | ||
|
||
### FailureMessage:setActual(actual) | ||
|
||
This function is used internally to set the value of `actual`. You usually do not need to call it yourself. | ||
|
||
### FailureMessage:toString() | ||
|
||
This function is used internally to create the displayed message from the pattern and the parameters. This | ||
function is called when calling `tostring(msg)` with a `FailureMessage` object. | ||
|
||
## DiffTable | ||
|
||
Objects of type `DiffTable` are containing an `initial` table and a `diffs` array to identify differences | ||
with another table. To create a `DiffTable`, simply call `DiffTable(initial, diffs)`, but you usually should | ||
not need to create such object as it is created automatically when comparing tables. | ||
|
||
A `DiffTable` object can be directly provided as a `FailureMessage` parameter and will be displayed with the | ||
differences highlighted. | ||
|
||
### DiffTable.isInstance(item) | ||
|
||
This function can be called on any object in order to check if this object is a `DiffTable` object. The | ||
result is `true` if it is the case, `false` otherwise. | ||
|
||
### DiffTable.compare(item1, item2) | ||
|
||
This function compares the two provided items. If they are tables, they will be deep compared. The result of | ||
the comparison is a boolean (`true` if objects are same) and either a copy of each object or a `DiffTable` | ||
instead of each object if it makes sense. |
Oops, something went wrong.