diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 329fbdab..71b6087b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,165 +1,361 @@ on: pull_request: - types: [opened, synchronize, reopened] + types: [ opened, synchronize, reopened ] push: branches: - master - "[1-9].x" -name: Continuous integration +name: CI jobs: ci: - name: Build and test runs-on: ubuntu-latest - strategy: - matrix: - rust: - - stable - - beta + # Keep this the same as this is what Github looks for to determine if the build passed + name: "Pass" + needs: + - check_style + - minimum_rust_version + - docs + - test + steps: + - run: exit 0 - services: - postgres: - image: postgres:11.6 - env: - POSTGRES_PASSWORD: '' - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - mysql: - image: mysql:8 - env: - MYSQL_ROOT_PASSWORD: '' - MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' - ports: - - 3306:3306 + check_style: + name: Check file formatting and style + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + components: clippy, rustfmt + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: clippy-cargo-${{ hashFiles('**/Cargo.toml') }} + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install libpq-dev + + - name: Check file formatting + run: cargo fmt --all -- --check + + - name: Run clippy + run: cargo clippy --workspace --all-features + + minimum_rust_version: + name: Check minimum rust version + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.60.0 - name: Cache cargo registry - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git - key: ${{ runner.os }}-${{ matrix.backend }}-cargo-${{ hashFiles('**/Cargo.toml') }} + key: minimal_rust_version-cargo-${{ hashFiles('**/Cargo.toml') }} - name: Install dependencies run: | sudo apt-get update sudo apt-get -y install libpq-dev - - name: Install toolchain - uses: dtolnay/rust-toolchain@stable + - name: Use minimal dependencies + run: | + RUSTC_BOOTSTRAP=1 cargo update -Z minimal-versions + + - name: Check build + run: cargo check --workspace + + docs: + name: "Check documentation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: docs-cargo-${{ hashFiles('**/Cargo.toml') }} + + - name: Check documentation + env: + RUSTDOCFLAGS: --cfg docsrs + run: cargo doc --no-deps --all-features + + test: + name: "Test" + runs-on: ubuntu-latest + needs: + - standard_tests + - dependency_tests + - database_tests + - fuzz_tests + steps: + - run: exit 0 + + standard_tests: + name: "Standard Tests" + runs-on: ubuntu-latest + strategy: + # There doesn't seem to be a way to share the matrix between jobs + matrix: + name: + - stable + - beta + include: + # This allows us to define targets in the future (e.g. wasm32-unknown-unknown) + - name: stable + rust: stable + - name: beta + rust: beta + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: tests-std-${{ matrix.rust }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.toml') }} - uses: davidB/rust-cargo-make@v1 - - name: Build rust-decimal - run: cargo build --workspace --all-features # Important to keep this to ensure docs.rs passes + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install libpq-dev - name: Run no_std tests run: cargo make test-no-std + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - name: Run default tests run: cargo make test-default + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - name: Run legacy operation tests run: cargo make test-legacy-ops + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - name: Run mathematical function tests run: cargo make test-maths + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - - name: Run miscellaneous tests - run: cargo make test-misc + - name: Run macro tests + run: cargo make test-macros + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - - name: Run database tests - run: cargo make test-db + dependency_tests: + name: "Dependency Tests" + runs-on: ubuntu-latest + strategy: + # There doesn't seem to be a way to share the matrix between jobs + matrix: + name: + - stable + - beta + include: + # This allows us to define targets in the future (e.g. wasm32-unknown-unknown) + - name: stable + rust: stable + - name: beta + rust: beta + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: tests-dep-${{ matrix.rust }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.toml') }} + + - uses: davidB/rust-cargo-make@v1 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install libpq-dev - name: Run serde tests run: cargo make test-serde + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - - name: Run macro tests - run: cargo make test-macros + - name: Run miscellaneous dependency tests + run: cargo make test-misc + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - check_style: - name: Check file formatting and style + database_tests: + name: "Database Tests" runs-on: ubuntu-latest + needs: + - postgres_tests + - mysql_tests steps: - - uses: actions/checkout@v3 + - run: exit 0 + + postgres_tests: + name: "Database Tests - PostgreSQL" + runs-on: ubuntu-latest + strategy: + # There doesn't seem to be a way to share the matrix between jobs + matrix: + name: + - stable + - beta + include: + # This allows us to define targets in the future (e.g. wasm32-unknown-unknown) + - name: stable + rust: stable + - name: beta + rust: beta + services: + postgres: + image: postgres:11.6 + env: + POSTGRES_PASSWORD: '' + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - components: clippy, rustfmt + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} - name: Cache cargo registry - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git - key: clippy-cargo-${{ hashFiles('**/Cargo.toml') }} + key: tests-pgsql-${{ matrix.rust }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.toml') }} + + - uses: davidB/rust-cargo-make@v1 - name: Install dependencies run: | sudo apt-get update sudo apt-get -y install libpq-dev - - name: Check file formatting - run: cargo fmt --all -- --check - - - name: Run clippy - run: cargo clippy --workspace --all-features + - name: Run database tests + run: cargo make test-db-postgres-all + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - fuzz: - name: Fuzz + mysql_tests: + name: "Database Tests - MySQL" runs-on: ubuntu-latest + strategy: + # There doesn't seem to be a way to share the matrix between jobs + matrix: + name: + - stable + - beta + include: + # This allows us to define targets in the future (e.g. wasm32-unknown-unknown) + - name: stable + rust: stable + - name: beta + rust: beta + services: + mysql: + image: mysql:8 + env: + MYSQL_ROOT_PASSWORD: '' + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + ports: + - 3306:3306 steps: - - name: Checkout repository - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@stable with: - toolchain: nightly + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} - - name: Install Cargo Fuzz - run: cargo install cargo-fuzz + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: tests-mysql-${{ matrix.rust }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.toml') }} - uses: davidB/rust-cargo-make@v1 - - name: Run fuzz tests - run: cargo make fuzz + - name: Run database tests + run: cargo make test-db-mysql-all + env: + CI_DECIMAL_TEST_TARGET: ${{ matrix.target }} - minimum_rust_version: - name: Check minimum rust version + fuzz_tests: + name: Fuzz Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.60.0 + toolchain: nightly - name: Cache cargo registry - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git - key: minimal_rust_version-cargo-${{ hashFiles('**/Cargo.toml') }} + key: tests-fuzz-${{ matrix.rust }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.toml') }} - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get -y install libpq-dev + - name: Install Cargo Fuzz + run: cargo install cargo-fuzz - - name: Use minimal dependencies - run: | - RUSTC_BOOTSTRAP=1 cargo update -Z minimal-versions + - uses: davidB/rust-cargo-make@v1 - - name: Check build - run: cargo check --workspace + - name: Run fuzz tests + run: cargo make fuzz diff --git a/make/tests/misc.toml b/make/tests/misc.toml index 06095b42..a1499710 100644 --- a/make/tests/misc.toml +++ b/make/tests/misc.toml @@ -10,28 +10,28 @@ dependencies = [ [tasks.test-proptest] command = "cargo" -args = ["test", "--workspace", "--no-default-features", "--features=proptest", "--", "--skip", "generated"] +args = ["test", "--workspace", "--no-default-features", "--features=proptest", "proptest_tests", "--", "--skip", "generated"] [tasks.test-rust-fuzz] command = "cargo" -args = ["test", "--workspace", "--no-default-features", "--features=rust-fuzz", "rust_fuzz", "--", "--skip", "generated"] +args = ["test", "--workspace", "--no-default-features", "--features=rust-fuzz", "rust_fuzz_tests", "--", "--skip", "generated"] [tasks.test-rocket-traits] command = "cargo" -args = ["test", "--workspace", "--features=rocket-traits"] +args = ["test", "--workspace", "--features=rocket-traits", "rocket_tests"] [tasks.test-borsh] command = "cargo" -args = ["test", "--workspace", "--features=borsh", "--", "--skip", "generated"] +args = ["test", "--workspace", "--features=borsh", "borsh_tests", "--", "--skip", "generated"] [tasks.test-ndarray] command = "cargo" -args = ["test", "--workspace", "--features=ndarray", "--", "--skip", "generated"] +args = ["test", "--workspace", "--features=ndarray", "nd_array_tests", "--", "--skip", "generated"] [tasks.test-rkyv] command = "cargo" -args = ["test", "--workspace", "--features=rkyv", "--features=rkyv-safe", "--", "--skip", "generated"] +args = ["test", "--workspace", "--features=rkyv", "--features=rkyv-safe", "rkyv_tests", "--", "--skip", "generated"] [tasks.test-rand] command = "cargo" -args = ["test", "--workspace", "--features=rand", "--", "--skip", "generated"] +args = ["test", "--workspace", "--features=rand", "rand_tests", "--", "--skip", "generated"] diff --git a/src/rand.rs b/src/rand.rs index afd8a643..991c60d2 100644 --- a/src/rand.rs +++ b/src/rand.rs @@ -125,7 +125,7 @@ fn sync_scales(mut a: Decimal, mut b: Decimal) -> (Decimal, Decimal) { } #[cfg(test)] -mod tests { +mod rand_tests { use std::collections::HashSet; use super::*; diff --git a/tests/decimal_tests.rs b/tests/decimal_tests.rs index 03ad08e6..e716fd11 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -128,103 +128,117 @@ fn it_can_serialize_deserialize() { } } -#[test] #[cfg(feature = "borsh")] -fn it_can_serialize_deserialize_borsh() { - let tests = [ - "12.3456789", - "5233.9008808150288439427720175", - "-5233.9008808150288439427720175", - ]; - for test in &tests { - let a = Decimal::from_str(test).unwrap(); - let mut bytes: Vec = Vec::new(); - borsh::BorshSerialize::serialize(&a, &mut bytes).unwrap(); - let b: Decimal = borsh::BorshDeserialize::deserialize(&mut bytes.as_slice()).unwrap(); - assert_eq!(test.to_string(), b.to_string()); - let bytes = borsh::try_to_vec_with_schema(&a); - assert!(bytes.is_ok(), "try_to_vec_with_schema.is_ok()"); - let bytes = bytes.unwrap(); - let result = borsh::try_from_slice_with_schema(&bytes); - assert!(result.is_ok(), "try_from_slice_with_schema.is_ok()"); - let b: Decimal = result.unwrap(); - assert_eq!(test.to_string(), b.to_string()); +mod borsh_tests { + use rust_decimal::Decimal; + use std::str::FromStr; + + #[test] + fn it_can_serialize_deserialize_borsh() { + let tests = [ + "12.3456789", + "5233.9008808150288439427720175", + "-5233.9008808150288439427720175", + ]; + for test in &tests { + let a = Decimal::from_str(test).unwrap(); + let mut bytes: Vec = Vec::new(); + borsh::BorshSerialize::serialize(&a, &mut bytes).unwrap(); + let b: Decimal = borsh::BorshDeserialize::deserialize(&mut bytes.as_slice()).unwrap(); + assert_eq!(test.to_string(), b.to_string()); + let bytes = borsh::try_to_vec_with_schema(&a); + assert!(bytes.is_ok(), "try_to_vec_with_schema.is_ok()"); + let bytes = bytes.unwrap(); + let result = borsh::try_from_slice_with_schema(&bytes); + assert!(result.is_ok(), "try_from_slice_with_schema.is_ok()"); + let b: Decimal = result.unwrap(); + assert_eq!(test.to_string(), b.to_string()); + } } } -#[test] #[cfg(feature = "ndarray")] -fn it_can_do_scalar_ops_in_ndarray() { - use ndarray::Array1; - use num_traits::FromPrimitive; +mod ndarray_tests { + use rust_decimal::Decimal; - let array_a = Array1::from(vec![ - Decimal::from_f32(1.0).unwrap(), - Decimal::from_f32(2.0).unwrap(), - Decimal::from_f32(3.0).unwrap(), - ]); - - // Add - let output = array_a.clone() + Decimal::from_f32(5.0).unwrap(); - let expectation = Array1::from(vec![ - Decimal::from_f32(6.0).unwrap(), - Decimal::from_f32(7.0).unwrap(), - Decimal::from_f32(8.0).unwrap(), - ]); - assert_eq!(output, expectation); - - // Sub - let output = array_a.clone() - Decimal::from_f32(5.0).unwrap(); - let expectation = Array1::from(vec![ - Decimal::from_f32(-4.0).unwrap(), - Decimal::from_f32(-3.0).unwrap(), - Decimal::from_f32(-2.0).unwrap(), - ]); - assert_eq!(output, expectation); - - // Mul - let output = array_a.clone() * Decimal::from_f32(5.0).unwrap(); - let expectation = Array1::from(vec![ - Decimal::from_f32(5.0).unwrap(), - Decimal::from_f32(10.0).unwrap(), - Decimal::from_f32(15.0).unwrap(), - ]); - assert_eq!(output, expectation); - - // Div - let output = array_a / Decimal::from_f32(5.0).unwrap(); - let expectation = Array1::from(vec![ - Decimal::from_f32(0.2).unwrap(), - Decimal::from_f32(0.4).unwrap(), - Decimal::from_f32(0.6).unwrap(), - ]); - assert_eq!(output, expectation); + #[test] + fn it_can_do_scalar_ops_in_ndarray() { + use ndarray::Array1; + use num_traits::FromPrimitive; + + let array_a = Array1::from(vec![ + Decimal::from_f32(1.0).unwrap(), + Decimal::from_f32(2.0).unwrap(), + Decimal::from_f32(3.0).unwrap(), + ]); + + // Add + let output = array_a.clone() + Decimal::from_f32(5.0).unwrap(); + let expectation = Array1::from(vec![ + Decimal::from_f32(6.0).unwrap(), + Decimal::from_f32(7.0).unwrap(), + Decimal::from_f32(8.0).unwrap(), + ]); + assert_eq!(output, expectation); + + // Sub + let output = array_a.clone() - Decimal::from_f32(5.0).unwrap(); + let expectation = Array1::from(vec![ + Decimal::from_f32(-4.0).unwrap(), + Decimal::from_f32(-3.0).unwrap(), + Decimal::from_f32(-2.0).unwrap(), + ]); + assert_eq!(output, expectation); + + // Mul + let output = array_a.clone() * Decimal::from_f32(5.0).unwrap(); + let expectation = Array1::from(vec![ + Decimal::from_f32(5.0).unwrap(), + Decimal::from_f32(10.0).unwrap(), + Decimal::from_f32(15.0).unwrap(), + ]); + assert_eq!(output, expectation); + + // Div + let output = array_a / Decimal::from_f32(5.0).unwrap(); + let expectation = Array1::from(vec![ + Decimal::from_f32(0.2).unwrap(), + Decimal::from_f32(0.4).unwrap(), + Decimal::from_f32(0.6).unwrap(), + ]); + assert_eq!(output, expectation); + } } -#[test] #[cfg(feature = "rkyv")] -fn it_can_serialize_deserialize_rkyv() { - use rkyv::Deserialize; - let tests = [ - "12.3456789", - "5233.9008808150288439427720175", - "-5233.9008808150288439427720175", - ]; - for test in &tests { - let a = Decimal::from_str(test).unwrap(); - let bytes = rkyv::to_bytes::<_, 256>(&a).unwrap(); +mod rkyv_tests { + use rust_decimal::Decimal; + use std::str::FromStr; - #[cfg(feature = "rkyv-safe")] - { - let archived = rkyv::check_archived_root::(&bytes[..]).unwrap(); - assert_eq!(archived, &a); - } + #[test] + fn it_can_serialize_deserialize_rkyv() { + use rkyv::Deserialize; + let tests = [ + "12.3456789", + "5233.9008808150288439427720175", + "-5233.9008808150288439427720175", + ]; + for test in &tests { + let a = Decimal::from_str(test).unwrap(); + let bytes = rkyv::to_bytes::<_, 256>(&a).unwrap(); + + #[cfg(feature = "rkyv-safe")] + { + let archived = rkyv::check_archived_root::(&bytes[..]).unwrap(); + assert_eq!(archived, &a); + } - let archived = unsafe { rkyv::archived_root::(&bytes[..]) }; - assert_eq!(archived, &a); + let archived = unsafe { rkyv::archived_root::(&bytes[..]) }; + assert_eq!(archived, &a); - let deserialized: Decimal = archived.deserialize(&mut rkyv::Infallible).unwrap(); - assert_eq!(deserialized, a); + let deserialized: Decimal = archived.deserialize(&mut rkyv::Infallible).unwrap(); + assert_eq!(deserialized, a); + } } } @@ -4706,7 +4720,7 @@ mod generated { } #[cfg(feature = "proptest")] -mod proptest { +mod proptest_tests { use super::Decimal; use proptest::prelude::*; @@ -4720,7 +4734,7 @@ mod proptest { #[cfg(feature = "rocket-traits")] #[allow(clippy::disallowed_names)] -mod rocket { +mod rocket_tests { use crate::Decimal; use rocket::form::{Form, FromForm}; use std::str::FromStr; @@ -4743,7 +4757,7 @@ mod rocket { } #[cfg(feature = "rust-fuzz")] -mod rust_fuzz { +mod rust_fuzz_tests { use arbitrary::{Arbitrary, Unstructured}; use super::*;