Fluent test assertions for Rust.

Overview

This is a fork the unmaintained crate spectral. Spectral as not changed for five years and yet is still very usable, the goal of this fork is to add new assertion capabilities without breaking the existing API.

speculoos

Crates.io CI codecov GitHub

Fluent test assertions for Rust.

Influenced by Google Truth and other fluent assertion frameworks.

Usage

Add this to your Cargo.toml:

[dependencies]
speculoos = "0.6.0"

Then add this to your crate:

extern crate speculoos;

To quickly start using assertions, simply use the prelude module in your test module:

use speculoos::prelude::*;

Overview

Speculoos allows you to write your assertions in a fluent manner by seperating out what you are testing with, what you are testing against and how you are asserting.

Simple asserts

For example, to test that a produced value is equal to an expected value, you would write:

assert_that(&1).is_equal_to(&1);

Or that a Vec contains a certain number of elements:

let test_vec = vec![1,2,3];
assert_that(&test_vec).has_length(3);

The methods avaliable for asserting depend upon the type under test and what traits are implemented.

As described below, it's recommended to use the macro form of assert_that! to provide correct file and line numbers for failing assertions.

Failure messages

For failing assertions, the usual panic message follows the following format:

    expected: <2>
     but was: <1>

To add additional clarification to the panic message, you can also deliberately state what you are asserting by calling the asserting(...) function rather than assert_that(...):

asserting(&"test condition").that(&1).is_equal_to(&2);

Which will produce:

    test condition:
    expected: <2>
     but was: <1>

Using the macro form of assert_that! will provide you with the file and line of the failing assertion as well:

    expected: vec to have length <2>
     but was: <1>

    at location: tests/parser.rs:112

Named Subjects

To make it more obvious what your subject actually is, you can call .named(...) after assert_that (or asserting(...).that(...)), which will print out the provided &str as the subject name if the assertion fails.

assert_that(&thing.attributes).named(&"thing attributes").has_length(2);

On failure, this will display:

    for subject [thing attributes]
    expected: vec to have length <2>
     but was: <1>

Mapping values

If you want to assert against a value contained within a struct, you can call map(...) with a closure, which will create a new Spec based upon the return value of the closure. You can then call any applicable assertions against the mapped value.

let test_struct = TestStruct { value: 5 };
assert_that(&test_struct).map(|val| &val.value).is_equal_to(&5);

Macros

If you add #[macro_use] to the extern crate declaration, you can also use the macro form of assert_that and asserting.

assert_that!(test_vec).has_length(5)

This allows you to pass through a subject to test without needing to deliberately turn it into a reference. However, for consistency, you can also use a deliberate reference in the macro as well.

assert_that!(&test_vec).has_length(5)

Additionally, this will provide you with the file and line number of the failing assertion (rather than just the internal speculoos panic location).

Assertions (Basic)

Note: Descriptions and examples for each of the assertions are further down in this readme.

General

is_equal_to

is_not_equal_to

matches

Booleans

is_true

is_false

Numbers

is_less_than

is_less_than_or_equal_to

is_greater_than

is_greater_than_or_equal_to

Floats (optional)

is_close_to

Options

is_some -> (returns a new Spec with the Option value)

is_none

contains_value

Paths

exists

does_not_exist

is_a_file

is_a_directory

has_file_name

Results

is_ok -> (returns a new Spec with the Ok value)

is_err -> (returns a new Spec with the Err value)

is_ok_containing

is_err_containing

Strings

starts_with

ends_with

contains

is_empty

Vectors

has_length

is_empty

HashMaps

has_length

is_empty

contains_key -> (returns a new Spec with the key value)

does_not_contain_key

contains_entry

does_not_contain_entry

IntoIterator/Iterator

contains

does_not_contain

contains_all_of

mapped_contains

equals_iterator

IntoIterator

matching_contains

Optional Features

Num Crate

The num crate is used for Float assertions. This feature will be enabled by default, but if you don't want the dependency on num, then simply disable it.

Assertions (Detailed)

As a general note, any type under test will usually need to implement at least Debug. Other assertions will have varying bounds attached to them.

General

is_equal_to

Asserts that the subject and the expected value are equal. The subject type must implement PartialEq.

Example
assert_that(&"hello").is_equal_to(&"hello");
Failure Message
	expected: <2>
	 but was: <1>

is_not_equal_to

Asserts that the subject and the expected value are not equal. The subject type must implement PartialEq.

Example
assert_that(&"hello").is_not_equal_to(&"hello");
Failure Message
	expected: <1> not equal to <1>
	 but was: equal

matches

Accepts a function accepting the subject type which returns a bool. Returning false will cause the assertion to fail.

NOTE: The resultant panic message will only state the actual value. It's recommended that you write your own assertions rather than relying upon this.

Example
assert_that(&"Hello").matches(|val| val.eq(&"Hello"));
Failure Message
">
	expectation failed for value <"Hello">

Booleans

is_true

Asserts that the subject is true. The subject type must be bool.

Example
assert_that(&true).is_true(); 
Failure Message
	expected: bool to be <true>
	 but was: <false>

is_false

Asserts that the subject is false. The subject type must be bool.

Example
assert_that(&false).is_false();
Failure Message
	expected: bool to be <false>
	 but was: <true>

Numbers

is_less_than

Asserts that the subject value is less than the expected value. The subject type must implement PartialOrd.

Example
assert_that(&1).is_less_than(&2);
Failure Message
	expected: value less than <2>
	 but was: <3>

is_less_than_or_equal_to

Asserts that the subject is less than or equal to the expected value. The subject type must implement PartialOrd.

Example
assert_that(&2).is_less_than_or_equal_to(&2);
Failure Message
	expected: value less than or equal to <2>
	 but was: <3>

is_greater_than

Asserts that the subject is greater than the expected value. The subject type must implement PartialOrd.

Example
assert_that(&2).is_greater_than(&1);
Failure Message
	expected: value greater than <3>
	 but was: <2>

is_greater_than_or_equal_to

Asserts that the subject is greater than or equal to the expected value. The subject type must implement PartialOrd.

Example
assert_that(&2).is_greater_than_or_equal_to(&1); 
Failure Message
	expected: value greater than or equal to <3>
	 but was: <2>

Floats (optional)

is_close_to

Asserts that the subject is close to the expected value by the specified tolerance. The subject type must implement Float and Debug.

Example
assert_that(&2.0f64).is_close_to(2.0f64, 0.01f64);
Failure Message
	expected: float close to <1> (tolerance of <0.01>)
	 but was: <2>

Options

is_some -> (returns a new Spec with the Option value)

Asserts that the subject is Some. The subject type must be an Option.

This will return a new Spec containing the unwrapped value if it is Some.

Example
assert_that(&Some(1)).is_some();
Chaining
assert_that(&option).is_some().is_equal_to(&"Hello");
Failure Message
	expected: option[some]
	 but was: option[none]

is_none

Asserts that the subject is None. The value type must be an Option.

Example
assert_that(&Option::None::<String>).is_none();
Failure Message
">
	expected: option[none]
	 but was: option<"Hello">

contains_value

Asserts that the subject is a Some containing the expected value. The subject type must be an Option.

Example
assert_that(&Some(1)).contains_value(&1);
Failure Message
but was: <"Hello"> ">
	expected: option to contain <"Hi">
	 but was: <"Hello">

Paths

exists

Asserts that the subject Path or PathBuf refers to an existing location.

Example
assert_that(&Path::new("/tmp/file")).exists();
Failure Message
to exist but was: a non-existent Path ">
	expected: Path of <"/tmp/file"> to exist
	 but was: a non-existent Path

does_not_exist

Asserts that the subject Path or PathBuf does not refer to an existing location.

Example
assert_that(&Path::new("/tmp/file")).does_not_exist();
Failure Message
to not exist but was: a resolvable Path ">
	expected: Path of <"/tmp/file"> to not exist
     but was: a resolvable Path

is_a_file

Asserts that the subject Path or PathBuf refers to an existing file.

Example
assert_that(&Path::new("/tmp/file")).is_a_file();
Failure Message
to be a file but was: not a resolvable file ">
	expected: Path of <"/tmp/file"> to be a file
	 but was: not a resolvable file

is_a_directory

Asserts that the subject Path or PathBuf refers to an existing directory.

Example
assert_that(&Path::new("/tmp/dir/")).is_a_directory();
Failure Message
to be a directory but was: not a resolvable directory ">
	expected: Path of <"/tmp/dir/"> to be a directory
	 but was: not a resolvable directory

has_file_name

Asserts that the subject Path or PathBuf has the expected file name.

Example
assert_that(&Path::new("/tmp/file")).has_file_name(&"file");
Failure Message
	expected: Path with file name of <pom.xml>
	 but was: <Cargo.toml>

Results

is_ok -> (returns a new Spec with the Ok value)

Asserts that the subject is Ok. The value type must be a Result.

This will return a new Spec containing the unwrapped value if it is Ok.

Example
assert_that(&Result::Ok::<usize, usize>(1)).is_ok();
Chaining
let result: Result<&str, &str> = Ok("Hello");
assert_that(&result).is_ok().is_equal_to(&"Hello");
Failure Message
">
	expected: result[ok]
	 but was: result[error]<"Oh no">

is_err -> (returns a new Spec with the Err value)

Asserts that the subject is Err. The value type must be a Result.

This will return a new Spec containing the unwrapped value if it is Err.

Note: This used to be called is_error, but has been renamed to match standard Rust naming.

Example
assert_that(&Result::Err::<usize, usize>(1)).is_err();
Chaining
let result: Result<&str, &str> = Err("Hello");
assert_that(&result).is_err().is_equal_to(&"Hello");
Failure Message
">
	expected: result[error]
	 but was: result[ok]<"Hello">

is_ok_containing

Asserts that the subject is an Ok Result containing the expected value. The subject type must be a Result.

Example
assert_that(&Result::Ok::<usize, usize>(1)).is_ok_containing(&1);
Failure Message
but was: Result[ok] containing <"Hello"> ">
	expected: Result[ok] containing <"Hi">
	 but was: Result[ok] containing <"Hello">

is_err_containing

Asserts that the subject is an Err Result containing the expected value. The subject type must be a Result.

Example
assert_that(&Result::Err::<usize, usize>(1)).is_err_containing(&1);
Failure Message
but was: Result[err] containing <"Whoops"> ">
	expected: Result[err] containing <"Oh no">
	 but was: Result[err] containing <"Whoops">

Strings

starts_with

Asserts that the subject &str or String starts with the provided &str.

Example
assert_that(&"Hello").starts_with(&"H");
Failure Message
but was: <"Hello"> ">
	expected: string starting with <"A">
	 but was: <"Hello">

ends_with

Asserts that the subject &str or String ends with the provided &str.

Example
assert_that(&"Hello").ends_with(&"o");
Failure Message
but was: <"Hello"> ">
	expected: string ending with <"A">
	 but was: <"Hello">

contains

Asserts that the subject &str or String contains the provided &str.

Example
assert_that(&"Hello").contains(&"e");

does_not_contain

Asserts that the subject &str or String does not contain the provided &str.

Example
assert_that(&"Hello").does_not_contain(&"Bonjour");
Failure Message
but was: <"Hello"> ">
	expected: string containing <"A">
	 but was: <"Hello">

is_empty

Asserts that the subject &str or String represents an empty string.

Example
assert_that(&"").is_empty();
Failure Message
">
	expected: an empty string
	 but was: <"Hello">

Vectors

has_length

Asserts that the length of the subject vector is equal to the provided length. The subject type must be of Vec.

Example
assert_that(&vec![1, 2, 3, 4]).has_length(4);
Failure Message
	expected: vec to have length <1>
	 but was: <3>

is_empty

Asserts that the subject vector is empty. The subject type must be of Vec.

Example
let test_vec: Vec<u8> = vec![];
assert_that(&test_vec).is_empty();
Failure Message
	expected: an empty vec
	 but was: a vec with length <1>

HashMaps

has_length

Asserts that the length of the subject hashmap is equal to the provided length. The subject type must be of HashMap.

Example
let mut test_map = HashMap::new();
test_map.insert(1, 1);
test_map.insert(2, 2);

assert_that(&test_map).has_length(2);
Failure Message
	expected: hashmap to have length <1>
	 but was: <2>

is_empty

Asserts that the subject hashmap is empty. The subject type must be of HashMap.

Example
let test_map: HashMap<u8, u8> = HashMap::new();
assert_that(&test_map).is_empty();
Failure Message
	expected: an empty hashmap
	 but was: a hashmap with length <1>

contains_key -> (returns a new Spec with the key value)

Asserts that the subject hashmap contains the expected key. The subject type must be of HashMap.

This will return a new Spec containing the associated value if the key is present.

Example
let mut test_map = HashMap::new();
test_map.insert("hello", "hi");

assert_that(&test_map).contains_key(&"hello");
Chaining
let mut test_map = HashMap::new();
test_map.insert("hello", "hi");

assert_that(&test_map).contains_key(&"hello").is_equal_to(&"hi");
Failure Message
but was: <["hey", "hi"]> ">
	expected: hashmap to contain key <"hello">
	 but was: <["hey", "hi"]>

does_not_contain_key

Asserts that the subject hashmap does not contain the provided key. The subject type must be of HashMap.

Example
let mut test_map = HashMap::new();
test_map.insert("hello", "hi");

assert_that(&test_map).does_not_contain_key(&"hey");
Failure Message
but was: present in hashmap ">
	expected: hashmap to not contain key <"hello">
	 but was: present in hashmap

contains_entry

Asserts that the subject hashmap contains the expected key with the expected value. The subject type must be of HashMap.

Example
let mut test_map = HashMap::new();
test_map.insert("hello", "hi");

assert_that(&test_map).contains_entry(&"hello", &"hi");
Failure Message
with value <"hey"> but was: key <"hi"> with value <"hello"> instead ">
    expected: hashmap containing key <"hi"> with value <"hey">
     but was: key <"hi"> with value <"hello"> instead

does_not_contain_entry

Asserts that the subject hashmap does not contain the provided key and value. The subject type must be of HashMap.

Example
let mut test_map = HashMap::new();
test_map.insert("hello", "hi");

assert_that(&test_map).does_not_contain_entry(&"hello", &"hey");
Failure Message
with value <"hi"> but was: present in hashmap ">
    expected: hashmap to not contain key <"hello"> with value <"hi">
     but was: present in hashmap

IntoIterator/Iterator

contains

Asserts that the subject contains the provided value. The subject must implement IntoIterator or Iterator, and the contained type must implement PartialEq and Debug.

Example
let test_vec = vec![1,2,3];
assert_that(&test_vec).contains(&2);
Failure Message
	expected: iterator to contain <1>
	 but was: <[5, 6]>

does_not_contain

Asserts that the subject does not contain the provided value. The subject must implement IntoIterator or Iterator, and the contained type must implement PartialEq and Debug.

Example
let test_vec = vec![1,2,3];
assert_that(&test_vec).does_not_contain(&4);
Failure Message
	expected: iterator to not contain <1>
	 but was: <[1, 2]>

contains_all_of

Asserts that the subject contains all of the provided values. The subject must implement IntoIterator or Iterator, and the contained type must implement PartialEq and Debug.

Example
let test_vec = vec![1, 2, 3];
assert_that(&test_vec.iter()).contains_all_of(&vec![&2, &3]);
Failure Message
    expected: iterator to contain items <[1, 6]>
     but was: <[1, 2, 3]>

mapped_contains

Maps the values of the subject before asserting that the mapped subject contains the provided value. The subject must implement IntoIterator, and the type of the mapped value must implement PartialEq.

NOTE: The panic message will refer to the mapped values rather than the values present in the original subject.

Example
#[derive(PartialEq, Debug)]
struct Simple {
    pub val: usize,
}

...

assert_that(&vec![Simple { val: 1 }, Simple { val: 2 } ]).mapped_contains(|x| &x.val, &2);
Failure Message
	expected: iterator to contain <5>
	 but was: <[1, 2, 3]>

equals_iterator

Asserts that the subject is equal to provided iterator. The subject must implement IntoIterator or Iterator, the contained type must implement PartialEq and Debug and the expected value must implement Iterator and Clone.

Example
let expected_vec = vec![1,2,3];
let test_vec = vec![1,2,3];
assert_that(&test_vec).equals_iterator(&expected_vec.iter());
Failure Message
	expected: Iterator item of <4> (read <[1, 2]>)
	 but was: Iterator item of <3> (read <[1, 2]>)

IntoIterator

matching_contains

Asserts that the subject contains a matching item by using the provided function. The subject must implement IntoIterator, and the contained type must implement Debug.

Example
let mut test_into_iter = LinkedList::new();
test_into_iter.push_back(TestEnum::Bad);
test_into_iter.push_back(TestEnum::Good);
test_into_iter.push_back(TestEnum::Bad);

assert_that(&test_into_iter).matching_contains(|val| {
    match val {
        &TestEnum::Good => true,
        _ => false
    }
});
Failure Message
expectation failed for iterator with values <[Bad, Bad, Bad]>

How it works

The Spec struct implements a number of different bounded traits which provide assertions based upon the bound type.

As a single example, length assertions are provided by the VecAssertions trait:

pub trait VecAssertions {            
    fn has_length(self, expected: usize);
} 

Which is then implemented by Spec:

impl<'s, T> VecAssertions for Spec<'s, Vec
   > {
    
   fn 
   has_length(
   self, expected: 
   usize) {
      ...
    }
} 
  

Naturally traits need to be included with a use before they apply, but to avoid an excessive number of use statements there is a prelude module which re-exports commonly used assertion traits.

Creating your own

To create your own assertions, simply create a new trait containing your assertion methods and implement Spec against it.

To fail an assertion, create a new AssertionFailure struct using from_spec(...) within your assertion method and pass in self.

AssertionFailure also implements builder methods with_expected(...), with_actual(...) and fail(...), which provides the necessary functionality to fail the test with the usual message format. If you need greater control of the failure message, you can call fail_with_message(...) which will directly print the provided message.

In either case, any description provided using asserting(...) will always be prepended to the panic message.

For example, to create an assertion that the length of a Vec is at least a certain value:

", expected)) .with_actual(format!("<{}>", subject.len())) .fail(); } } } ">
trait VecAtLeastLength {
    fn has_at_least_length(&mut self, expected: usize);
}

impl<'s, T> VecAtLeastLength for Spec<'s, Vec
   > {
    
   fn 
   has_at_least_length(
   &
   mut 
   self, expected: 
   usize) {
        
   let subject 
   = 
   self.subject;
        
   if expected 
   > subject.
   len() {
            AssertionFailure
   ::
   from_spec(
   self)
                .
   with_expected(
   format!(
   "vec with length at least <{}>", expected))
                .
   with_actual(
   format!(
   "<{}>", subject.
   len()))
                .
   fail();
        }
    }
}
  
Comments
  • Allow 'has_length' on maps without constraint on PartialEq for value

    Allow 'has_length' on maps without constraint on PartialEq for value

    This is a PR that originally have been opened on spectral (see https://github.com/cfrancia/spectral/pull/19). This reduces the constraints on some assertions on HashMap to allow some uses on has_length that were not possible before.

    opened by woshilapin 3
  • Implemented VecAssertions for referenced vectors

    Implemented VecAssertions for referenced vectors

    This is a transfer of the PR https://github.com/cfrancia/spectral/pull/12 which is coming from the original project spectral. Thanks to @kirushik for the contribution of code.

    opened by woshilapin 2
  • Have `matches()` return &mut Self

    Have `matches()` return &mut Self

    Having matches() return a reference to itself means that you can chain calls to it. IMHO this is the most convenient way to handle cases where you need to perform multiple assertions against the same entity. Alternatively, you could bundle a bunch of checks in the single closure by joining them all with &&. The downside of this is that it may be difficult to ascertain which assertion failed.

    opened by MrTact 0
  • Add `pretty_assertion` cargo feature

    Add `pretty_assertion` cargo feature

    The pretty assertion crate is helpful when dealing with large text assertions.

    The current assert_that implementation panic on failed assertions so it's not compatible with pretty_assertion out of the box.

    Maybe we could tweak assert_that so it uses assert_eq instead of panic so we can add pretty_assertions as a cargo feature.

    enhancement 
    opened by oknozor 1
  • Implement soft assertion

    Implement soft assertion

    it would be nice to have soft assertions.

    The API could look like this :

       let softly = SoftAssertions::new();
       softly.assert_that(mansion.guests()).as("Living guest").is_equal_to(7);
       softly.assert_that(mansion.kitchen()).as("Kitchen").is_equal_to("clean");
       softly.asser_that(mansion.library()).as("Library").is_equal_to("clean");
       softly.assert_all();
    

    resulting in the following :

     1) [Living Guests] expected:<[7]> but was:<[6]>
     2) [Library] expected:<"clean"> but was:<"messy">
     3) [Kitchen] expected:<"clean"> but was:<"dirty">
    
    enhancement 
    opened by oknozor 1
Owner
Paul Delafosse
Paul Delafosse
Travis CI and AppVeyor template to test your Rust crate on 5 architectures and publish binary releases of it for Linux, macOS and Windows

trust Travis CI and AppVeyor template to test your Rust crate on 5 architectures and publish binary releases of it for Linux, macOS and Windows Featur

Jorge Aparicio 1.2k Dec 30, 2022
Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.

An implementation of the Cucumber testing framework for Rust. Fully native, no external test runners or dependencies.

Brendan Molloy 394 Jan 1, 2023
A series of test cases to evaluate async Rust on the nrf52840 in terms of power usage and ergonomics.

A series of test cases to evaluate async Rust on the nrf52840 in terms of power usage and ergonomics. This is an experiment that uses unstable features only available on nightly rust.

Tweede golf 1 Oct 15, 2021
Test for rust-based plugin system for swc

rust-dylib-test Steps Run cargo build in plugin_a Ensure that plugin_a dynamically links to runtime/common by otool -L plugin_a/target/debug/libplugin

Donny/강동윤 1 Apr 6, 2022
Fixture-based test framework for Rust

Fixture-based test framework for Rust Introduction rstest uses procedural macros to help you on writing fixtures and table-based tests. To use it, add

Michele d'Amico 567 Dec 24, 2022
Verdun is a HTTP stress-test/benchmark tool written in Rust.

Verdun is a HTTP stress-test/benchmark tool written in Rust. ?? It supports testing a single URL, loading multiples URLs from a file or automatically navigating a website (auto discovery)

Alex Hortopan 2 Feb 23, 2022
Nextest is a next-generation test runner for Rust.

nextest Nextest is a next-generation test runner for Rust. For more, check out the website. This repository contains the source code for: cargo-nextes

null 1.3k Jan 8, 2023
`mutatis` is a library for writing custom, structure-aware test-case mutators for fuzzers in Rust.

mutatis Easily create custom, structure-aware mutators for fuzzing. Repository | Docs | Guide | Contributing About The most popular fuzzers — includin

Nick Fitzgerald 4 Aug 19, 2024
Test social media cards locally

Share Preview Test social media cards locally Description Preview and debug websites metadata tags for social media share. Third Party Packages Distri

Rafael Mardojai CM 65 Dec 25, 2022
Competitive Programming Stress Test Tools

Competitive Programming Stress Test Tools 競技プログラミング用 ストレステストツール このプログラムの役割 のプログラムに対して,それより実行時間がかかるが確実に できる愚直プログラムと比較することで, となるテストケースを探し出す 最大コーナーケースに対し

Ryusei Ishikawa 7 Aug 28, 2021
A heckin small test generator

heckcheck A heckin small test generator API Docs | Releases | Contributing Installation $ cargo add heckcheck Safety This crate uses #![deny(unsafe_co

Yoshua Wuyts 18 Mar 20, 2022
atttribute macro for running a flaky test multiple times

flaky_test This attribute macro will register and run a test 3 times, erroring only if all three times fail. Useful for situations when a test is flak

Deno Land 23 Mar 23, 2022
Test for crate delay_timer

delay_timer-test some test for crate delay_timer crate link: https://github.com/BinChengZhao/delay-timer here some test for delay_timer,also used for

null 1 Nov 22, 2021
a test harness for embedded devices

defmt-test a test harness for embedded devices This crate has been moved to the defmt repository Support defmt-test is part of the Knurling project, F

Knurling 8 Aug 27, 2022
Test cargo crates in different envs & via different methods

Test cargo crates in different envs & via different methods

@Vlad@ 2 Mar 22, 2022
Hopper is a tool for generating fuzzing test cases for libraries automatically using interpretative fuzzing.

Hopper Hopper is an tool for generating fuzzing test cases for libraries automatically using interpretative fuzzing. It transforms the problem of libr

FuzzAnything 118 Nov 15, 2023
Hopper is a tool for generating fuzzing test cases for libraries automatically using interpretative fuzzing.

Hopper Hopper is an tool for generating fuzzing test cases for libraries automatically using interpretative fuzzing. It transforms the problem of libr

FuzzAnything 124 Nov 24, 2023
Handle some lichess.org/tournament load with Rust, while learning Rust

lila-http Take some of the HTTP load away from lila. WIP! Arena tournaments Clients connected to a tournament page request new data about the tourname

Lichess 22 Jan 2, 2023
HTTP mocking library for Rust.

httpmock HTTP mocking library for Rust. Documentation · Crate · Report Bug · Request Feature · Changelog Features Simple, expressive, fluent API. Many

Alexander Liesenfeld 320 Dec 21, 2022