Skip to content

Commit de52423

Browse files
committed
feat: Make wasm32-compatible
Also include all other open PR's and suggestions to the original crate.
1 parent 3123138 commit de52423

8 files changed

Lines changed: 298 additions & 180 deletions

File tree

.cargo/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.wasm32-unknown-unknown]
2+
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]

.github/workflows/main.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Rust
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
rust:
13+
name: Build, lint, test
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
os: [ ubuntu-latest, windows-latest, macos-latest ]
18+
runs-on: ${{ matrix.os }}
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
23+
- name: Install stable toolchain
24+
uses: dtolnay/rust-toolchain@1.90.0
25+
with:
26+
components: rustfmt, clippy
27+
28+
- name: Install nextest
29+
uses: taiki-e/install-action@nextest
30+
31+
- name: Check max line length
32+
# rustfmt gives up on lines that are too long
33+
if: runner.os == 'Linux'
34+
run: "! grep -rP '^.{101}' --include='*.rs' ."
35+
36+
- name: Run fmt
37+
run: cargo fmt --all -- --check
38+
39+
- name: Build documentation
40+
run: cargo doc --no-deps --workspace --document-private-items
41+
env:
42+
RUSTDOCFLAGS: -D warnings
43+
44+
- name: Run clippy
45+
run: cargo clippy --all-targets -- -D warnings
46+
47+
- name: Run tests
48+
run: cargo nextest run --no-fail-fast --all-targets
49+
50+
# doctests are special [^1] but this step does not incur a performance penalty [^2]
51+
#
52+
# [^1]: https://nexte.st/book/usage.html#limitations
53+
# [^2]: https://github.com/nextest-rs/nextest/issues/16
54+
- name: Run documentation tests
55+
run: cargo test --doc

.github/workflows/wasm.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: WASM
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
wasm:
13+
name: Build, lint, test
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
19+
- name: Install stable toolchain
20+
uses: dtolnay/rust-toolchain@stable
21+
with:
22+
targets: wasm32-unknown-unknown
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v6
26+
with:
27+
node-version: '20'
28+
29+
- name: Install wasm-pack
30+
uses: taiki-e/install-action@v2
31+
with:
32+
tool: wasm-pack
33+
34+
- name: Build with wasm-pack
35+
run: wasm-pack build --release --target nodejs
36+
37+
- name: Run wasm-pack tests
38+
run: wasm-pack test --node

.gitignore

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,41 @@
1-
/target
2-
/Cargo.lock
1+
### Intellij ###
2+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
3+
4+
.idea/
5+
.idea_modules/
6+
7+
# Generated by Cargo
8+
# will have compiled files and executables
9+
debug/
10+
target/
11+
12+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
13+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
14+
Cargo.lock
15+
16+
# These are backup files generated by rustfmt
17+
**/*.rs.bk
18+
19+
# MSVC Windows builds of rustc generate these, which store debugging information
20+
*.pdb
21+
22+
### VisualStudioCode ###
23+
.vscode/*
24+
!.vscode/settings.json
25+
!.vscode/tasks.json
26+
!.vscode/launch.json
27+
!.vscode/extensions.json
28+
!.vscode/*.code-snippets
29+
30+
# Local History for Visual Studio Code
31+
.history/
32+
33+
# Built Visual Studio Code Extensions
34+
*.vsix
35+
36+
### VisualStudioCode Patch ###
37+
# Ignore all local history of files
38+
.history
39+
.ionide
40+
41+
# End of https://www.toptal.com/developers/gitignore/api/intellij,visualstudiocode,rust

Cargo.toml

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
11
[package]
2-
name = "proptest-arbitrary-interop"
3-
description = "Interop glue between arbitrary and proptest crates"
4-
authors = ["Graydon Hoare <graydon@pobox.com>"]
2+
name = "proptest-arbitrary-adapter"
53
version = "0.1.0"
6-
edition = "2021"
7-
license = "MIT OR Apache-2.0"
8-
keywords = ["property", "propcheck", "arbitrary", "fuzz", "testing"]
4+
authors = ["Graydon Hoare <graydon@pobox.com>", "Triton Software AG"]
5+
edition = "2024"
6+
description = "Make `arbitrary` interoperate with `proptest`."
7+
documentation = "https://docs.rs/crate/proptest-arbitrary-adapter/latest"
98
readme = "README.md"
9+
repository = "https://github.com/Neptune-Crypto/proptest-arbitrary-adapter"
10+
license = "MIT OR Apache-2.0"
11+
keywords = ["proptest", "arbitrary", "property", "fuzz", "testing"]
12+
categories = ["development-tools::testing"]
13+
14+
[lib]
15+
crate-type = ["cdylib", "rlib"]
1016

1117
[dependencies]
18+
arbitrary = "1.0.0"
19+
20+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
1221
proptest = "1.0.0"
13-
arbitrary = "1.1.3"
22+
23+
[target.'cfg(target_arch = "wasm32")'.dependencies]
24+
proptest = { version = "1.0.0", default-features = false, features = ["std"] }
25+
getrandom = { version = "0.3", features = ["wasm_js"] } # note: there is also a flag in .cargo/config.toml
26+
27+
[dev-dependencies]
28+
arbitrary = { version = "1.0.0", features = ["derive"] }
29+
test-strategy = "0.4"
30+
31+
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
32+
wasm-bindgen-test = "0.3.42"
33+
34+
[lints.rust]
35+
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] }

README.md

Lines changed: 22 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,36 @@
1-
# proptest-arbitrary-interop
1+
# proptest-arbitrary-adapter
22

3-
This crate provides the necessary glue to reuse an implementation of
4-
[`arbitrary::Arbitrary`] as a [`proptest::strategy::Strategy`].
3+
Provides the necessary glue to reuse an implementation of [`arbitrary::Arbitrary`][arbitrary] as a
4+
[`proptest::strategy::Strategy`][strategy].
55

6-
## Usage
6+
[arbitrary]: https://docs.rs/arbitrary/1.0.0/arbitrary/trait.Arbitrary.html
77

8-
in `Cargo.toml`:
8+
[strategy]: https://docs.rs/proptest/1.0.0/proptest/strategy/trait.Strategy.html
99

10-
```toml
11-
[dependencies]
12-
arbitrary = "1.1.3"
13-
proptest = "1.0.0"
14-
```
10+
## Usage
1511

16-
In your code:
12+
Assuming you use [`test-strategy`](https://crates.io/crates/test-strategy) (which you should), using a strategy for a
13+
type that implements `arbitrary::Arbitrary` is as simple as:
1714

1815
```rust
19-
20-
// Part 1: suppose you implement Arbitrary for one of your types
21-
// because you want to fuzz it.
22-
23-
use arbitrary::{Arbitrary, Result, Unstructured};
24-
#[derive(Copy, Clone, Debug)]
25-
pub struct Rgb {
26-
pub r: u8,
27-
pub g: u8,
28-
pub b: u8,
29-
}
30-
impl<'a> Arbitrary<'a> for Rgb {
31-
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
32-
let r = u8::arbitrary(u)?;
33-
let g = u8::arbitrary(u)?;
34-
let b = u8::arbitrary(u)?;
35-
Ok(Rgb { r, g, b })
36-
}
16+
#[proptest]
17+
fn my_test(#[strategy(arb())] my_type: MyType) {
18+
//
3719
}
20+
```
3821

39-
// Part 2: suppose you later decide that in addition to fuzzing
40-
// you want to use that Arbitrary impl, but with proptest.
22+
## Origin
4123

42-
use proptest::prelude::*;
43-
use proptest_arbitrary_interop::arb;
24+
This code is a copy of the unmaintained crate [`proptest-arbitrary-interop`][origin], with some additional improvements
25+
from open pull requests of the original's repository.
4426

45-
proptest! {
46-
#[test]
47-
#[should_panic]
48-
fn always_red(color in arb::<Rgb>()) {
49-
prop_assert!(color.g == 0 || color.r > color.g);
50-
}
51-
}
52-
```
27+
[origin]: https://crates.io/crates/proptest-arbitrary-interop
5328

5429
## Caveats
5530

56-
It only works with types that implement [`arbitrary::Arbitrary`] in a
57-
particular fashion: those conforming to the requirements of [`ArbInterop`].
58-
These are roughly "types that, when randomly-generated, don't retain
59-
pointers into the random-data buffer wrapped by the
60-
[`arbitrary::Unstructured`] they are generated from". Many implementations
61-
of [`arbitrary::Arbitrary`] will fit the bill, but certain kinds of
62-
"zero-copy" implementations of [`arbitrary::Arbitrary`] will not work. This
63-
requirement appears to be a necessary part of the semantic model of
64-
[`proptest`] -- generated values have to own their pointer graph, no
65-
borrows. Patches welcome if you can figure out a way to not require it.
66-
67-
This crate is based on
68-
[`proptest-quickcheck-interop`](https://crates.io/crates/proptest-quickcheck-interop)
69-
by Mazdak Farrokhzad, without whose work I wouldn't have had a clue how to
70-
approach this. The exact type signatures for the [`ArbInterop`] type are
71-
courtesy of Jim Blandy, who I hereby officially designate for-all-time as
72-
the Rust Puzzle King. Any errors I've introduced along the way are, of
73-
course, my own.
74-
75-
License: MIT OR Apache-2.0
31+
It only works with types that implement `arbitrary::Arbitrary` in a particular fashion: those conforming to the
32+
requirements of `ArbInterop`. These are roughly "types that, when randomly-generated, don't retain pointers into the
33+
random-data buffer wrapped by the `arbitrary::Unstructured` they are generated from". Many implementations of
34+
`arbitrary::Arbitrary` will fit the bill, but certain kinds of "zero-copy" implementations of `arbitrary::Arbitrary`
35+
will not work. This requirement appears to be a necessary part of the semantic model of `proptest` – generated values
36+
have to own their pointer graph, no borrows. Patches welcome if you can figure out a way to not require it.

0 commit comments

Comments
 (0)