Repository: tokio-rs/tokio
File: tokio/src/sync/semaphore.rs (Rust)

Code before:
/// }
/// # async fn handle_connection(_socket: &mut tokio::net::TcpStream) {
/// #   // Do work
/// # }
/// ```
///
/// ## Prevent tests from running in parallel
///
/// By default, Rust runs tests in the same file in parallel. However, in some cases, running two tests in parallel may lead to problems.
/// For example, this can happen when tests use the same database.
///
/// Consider the following scenario:
/// 1. `test_insert`: Inserts a key-value pair into the database, then retrieves the value using the same key to verify the insertion.
/// 2. `test_update`: Inserts a key, then updates the key to a new value and verifies that the value has been accurately updated.
/// 3. `test_others`: A third test that doesn't modify the database state. It can run in parallel with the other tests.
///
/// In this example, `test_insert` and `test_update` need to run in sequence to work, but it doesn't matter which test runs first.
/// We can leverage a semaphore with a single permit to address this challenge.
///
/// ```
/// use tokio::sync::{Semaphore, Mutex};
/// use lazy_static::lazy_static;
/// # use std::collections::HashMap;
/// # struct Database {
/// #   map: HashMap<String, i32>,
/// # }
/// # impl Database {
/// #    pub fn setup() -> Database {
/// #        Database {
/// #            map: HashMap::new(),
/// #        }
/// #    }
/// #    pub fn insert(&mut self, key: &str, value: i32) {
/// #        self.map.insert(key.to_string(), value);
/// #    }
/// #    pub fn update(&mut self, key: &str, value: i32) {
/// #        self.map
/// #            .entry(key.to_string())
/// #            .and_modify(|origin| *origin = value);
/// #    }
/// #    pub fn delete(&mut self, key: &str) {
/// #        self.map.remove(key);
/// #    }
/// #    pub fn get(&mut self, key: &str) -> i32 {
/// #        *self.map.get(key).unwrap()
/// #    }
/// # }
/// // Initialize a static semaphore with only one permit, which is used to
/// // prevent test_insert and test_update from running in parallel.
/// static PERMIT: Semaphore = Semaphore::const_new(1);
///

Review comment (suggestion):
Please move the mutex inside the database. That will let us hide it from the example itself.
```suggestion
/// # struct Database {
/// #   map: Mutex<HashMap<String, i32>>,
/// # }
```

Code after:
/// }
/// # async fn handle_connection(_socket: &mut tokio::net::TcpStream) {
/// #   // Do work
/// # }
/// ```
///
/// ## Prevent tests from running in parallel
///
/// By default, Rust runs tests in the same file in parallel. However, in some cases, running two tests in parallel may lead to problems.
/// For example, this can happen when tests use the same database.
///
/// Consider the following scenario:
/// 1. `test_insert`: Inserts a key-value pair into the database, then retrieves the value using the same key to verify the insertion.
/// 2. `test_update`: Inserts a key, then updates the key to a new value and verifies that the value has been accurately updated.
/// 3. `test_others`: A third test that doesn't modify the database state. It can run in parallel with the other tests.
///
/// In this example, `test_insert` and `test_update` need to run in sequence to work, but it doesn't matter which test runs first.
/// We can leverage a semaphore with a single permit to address this challenge.
///
/// ```
/// use tokio::sync::Semaphore;
/// # use tokio::sync::Mutex;
/// # use std::collections::BTreeMap;
/// # struct Database {
/// #   map: Mutex<BTreeMap<String, i32>>,
/// # }
/// # impl Database {
/// #    pub const fn setup() -> Database {
/// #        Database {
/// #            map: Mutex::const_new(BTreeMap::new()),
/// #        }
/// #    }
/// #    pub async fn insert(&self, key: &str, value: i32) {
/// #        self.map.lock().await.insert(key.to_string(), value);
/// #    }
/// #    pub async fn update(&self, key: &str, value: i32) {
/// #        self.map.lock().await
/// #            .entry(key.to_string())
/// #            .and_modify(|origin| *origin = value);
/// #    }
/// #    pub async fn delete(&self, key: &str) {
/// #        self.map.lock().await.remove(key);
/// #    }
/// #    pub async fn get(&self, key: &str) -> i32 {
/// #        *self.map.lock().await.get(key).unwrap()
/// #    }
/// # }
///
/// // Initialize a static semaphore with only one permit, which is used to
/// // prevent test_insert and test_update from running in parallel.
/// static PERMIT: Semaphore = Semaphore::const_new(1);