Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ build
coverage
node_modules
.idea
.vscode
compile_commands.json
29 changes: 18 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ To use Jazzer.js in your own project follow these few simple steps:
const fuzzerData = data.toString();
myAwesomeCode(fuzzerData);
};

// Alternatively, using ES6 syntax is also possible
export function fuzz(data /*: Buffer */) {
const fuzzerData = data.toString();
myAwesomeCode(fuzzerData);
}
```

3. Start the fuzzer using the fuzz target
Expand All @@ -77,10 +71,15 @@ To use Jazzer.js in your own project follow these few simple steps:
## Usage

Jazzer.js can be used in two ways: Creating dedicated fuzz targets, as shown in
the `Quickstart` section, or integrated into the Jest test framework.
the [`Quickstart`](#quickstart) section, or integrated into the
[Jest test framework](https://jestjs.io/).

### Using test framework integration

**Note**: Using the test framework integration is the easiest and most
convenient way to fuzz your code, hence, it is recommended to use this approach
whenever possible.

To use fuzzing in your normal development workflow, a tight integration with the
[Jest test framework](https://jestjs.io/) is provided. This coupling allows the
execution of fuzz tests alongside your normal unit tests and seamlessly detect
Expand All @@ -94,16 +93,24 @@ Jest tests.
**Note**: Detailed explanation on how to use the Jest integration can be found
at [docs/jest-integration.md](docs/jest-integration.md).

A fuzz test in Jest looks similar to the following example:
A Jest fuzz test, in this case written in TypeScript, looks similar to the
following example:

```js
describe("My function", () => {
it.fuzz("can be fuzzed", (data) => {
```typescript
// file: "Target.fuzz.ts"
import * as target from "./target";

describe("Target", () => {
it.fuzz("executes a method", (data: Buffer) => {
target.fuzzMe(data);
});
});
```

**Note**: Please take a look at
[Enabling TypeScript in Jest tests](docs/jest-integration.md#enabling-typescript-jest-tests)
for further information on how to set up Jest fuzz tests written in TypeScript.

### Using fuzz targets

Creating fuzz targets and executing those via CLI commands is straightforward
Expand Down
5 changes: 5 additions & 0 deletions docs/fuzz-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ as long as a module exporting a `fuzz` function is generated.
An example on how to use TypeScript to fuzz a library can be found at
[examples/js-yaml/package.json](../examples/js-yaml/package.json).

**Note**: Directly executing fuzz targets written in TypeScript is **NOT**
supported! However, it is possible to use the
[Jest integration](jest-integration.md) to execute Jest fuzz tests written in
TypeScript.

### ⚠️ Using Jazzer.js on pure ESM projects ⚠️

ESM brings a couple of challenges to the table, which are currently not fully
Expand Down
88 changes: 83 additions & 5 deletions docs/jest-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ normal Jest tests.
The Jest integration provides two modes of execution, which will be explained in
detail further down on this page.

- **Fuzzing Mode**: Fuzzing a function through a Jest test.
- **Regression Mode**: Using initially provided seeds and inputs of found
problems to execute the Jest test with.
- **[Fuzzing Mode](#fuzzing-mode)**: Fuzzing a function through a Jest test.
- **[Regression Mode](#regression-mode)**: Using initially provided seeds and
inputs of found problems to execute the Jest test with.

## Setting up the Jazzer.js Jest integration

Expand Down Expand Up @@ -87,6 +87,65 @@ which can be specified through the CLI client.
}
```

## Enabling TypeScript Jest tests

Jest supports execution of tests written in other languages than JavaScript via
dedicated extensions. Probably most prominent is its TypeScript support, which
can be enabled via [`ts-jest`](https://kulshekhar.github.io/ts-jest/).

We assume you already set up your TypeScript project according to the `ts-jest`
documentation. The following section shows a minimal configuration to enable
TypeScript support for Jest fuzz tests. Furthermore, an example project is
available at
[jest_typescript_integration](../examples/jest_typescript_integration).

In addition to the configuration shown in the last section, `ts-jest` has to be
added as dev-dependency to the project.

```shell
npm install --save-dev ts-jest
```

The Jazzer.js runner configuration also needs to reference `ts-jest`, most
commonly by setting the `preset` property to `ts-jest`. Also make sure to
actually include test files with the `.fuzz.ts` extension.

```typescript
{
displayName: {
name: "Jazzer.js",
color: "cyan",
},
preset: "ts-jest",
runner: "@jazzer.js/jest-runner",
testEnvironment: "node",
testMatch: ["<rootDir>/*.fuzz.[jt]s"],
},
```

To introduce the `fuzz` function types globally, add the following import to
`globals.d.ts`. This could also be done in the individual test files.

```typescript
import "@jazzer.js/jest-runner/jest-extension";
```

To provide accurate coverage reports for TypeScript fuzz tests, make sure to
enable source map generation in the TypeScript compiler options:

```json
{
"compilerOptions": {
"sourceMap": true
}
}
```

These settings should be enough to start writing Jest fuzz tests in TypeScript.

**Note**: Using custom hooks written in TypeScript is currently not supported,
as those are not pre-processed by Jest.

## Writing a Jest fuzz test

To create a fuzz test, the `fuzz` function on Jest's `test` and `it` can be
Expand Down Expand Up @@ -160,6 +219,26 @@ describe("My describe", () => {
)};
```

### TypeScript Jest fuzz tests

After the setup mentioned previously, Jest fuzz tests can be written in
TypeScript, just as one would expect.

**Note**: To satisfy TypeScript's type checker, add an import of
`@jazzer.js/jest-runner/jest-extension` in `globals.d.ts` or in the individual
test file.

```typescript
import "@jazzer.js/jest-runner/jest-extension";
import * as target from "./target";

describe("Target", () => {
it.fuzz("executes a method", (data: Buffer) => {
target.fuzzMe(data);
});
});
```

### Setup and teardown

The Jazzer.js fuzz test runner supports Jest's setup and teardown functions, as
Expand Down Expand Up @@ -299,7 +378,7 @@ To generate a coverage report, run jest with the `--coverage` flag:
npx jest --coverage
```

Note that unlike for the Jazzer.js CLI Jest only accepts the long flag of
**Note**: Unlike the Jazzer.js CLI, Jest only accepts the long flag of
`--coverage`!

Additional options for coverage report generation are described in the
Expand Down Expand Up @@ -337,4 +416,3 @@ reimplemented.

- Mock functions
- Isolated workers
- Typescript or any other non-Javascript test files
4 changes: 4 additions & 0 deletions examples/jest_typescript_integration/.jazzerjsrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"includes": ["target"],
"excludes": ["node_modules"]
}
63 changes: 63 additions & 0 deletions examples/jest_typescript_integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Jest Typscript Integration Example

Detailed documentation on the Jest integration is available in the main
[Jazzer.js](https://github.com/CodeIntelligenceTesting/jazzer.js/blob/main/docs/jest-integration.md)
documentation.

## Quickstart

To use the [Jest](https://jestjs.io/) integration install the
`@jazzer.js/jest-runner` and `ts-jest` packages then configure `jest-runner` as
a dedicated test runner in `package.json` or `jest.config.{ts|js}`.

The example below shows how to configure the Jazzer.js Jest integration in
combination with the normal Jest runner.

```json
"jest": {
"projects": [
{
"displayName": "Jest",
"preset": "ts-jest",
},
{
"displayName": {
"name": "Jazzer.js",
"color": "cyan",
},
"preset": "ts-jest",
"runner": "@jazzer.js/jest-runner",
"testEnvironment": "node",
"testMatch": ["<rootDir>/*.fuzz.[jt]s"],
},
],
"coveragePathIgnorePatterns": ["/node_modules/", "/dist/"],
"modulePathIgnorePatterns": ["/node_modules", "/dist/"],
}
```

Further configuration can be specified in `.jazzerjsrc`, like in any other
project, in the following format:

```json
{
"includes": ["*"],
"excludes": ["node_modules"],
[...]
}
```

Write a Jest fuzz test like:

```typescript
// file: jazzerjs.fuzz.ts
import "@jazzer.js/jest-runner/jest-extension";
describe("My describe", () => {
it.fuzz("My fuzz test", (data: Buffer) => {
target.fuzzMe(data);
});
});
```

**Note:** the `import` statement extends `jest`'s `It` interface to include the
`fuzz` property and is necessary for TypeScript to compile the test file.
1 change: 1 addition & 0 deletions examples/jest_typescript_integration/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "@jazzer.js/jest-runner/jest-extension";
38 changes: 38 additions & 0 deletions examples/jest_typescript_integration/integration.fuzz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2023 Code Intelligence GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Import the fuzz testing extension definition to compile TS code,
// or import it globally in globals.d.ts, like in this example.
// import "@jazzer.js/jest-runner/jest-extension";

import * as target from "./target";

describe("Target", () => {
it.fuzz("executes sync methods", (data: Buffer) => {
target.fuzzMe(data);
});

it.fuzz("executes async methods", async (data: Buffer) => {
await target.asyncFuzzMe(data);
});

it.fuzz(
"executes methods with a done callback",
(data: Buffer, done: (e?: Error) => void) => {
target.callbackFuzzMe(data, done);
}
);
});
39 changes: 39 additions & 0 deletions examples/jest_typescript_integration/integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2023 Code Intelligence GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint no-undef: 0 */

import * as target from "./target";

describe("My describe", () => {
it("My normal Jest test", () => {
expect(1).toEqual(1);
});

it("My done callback Jest test", (done) => {
expect(1).toEqual(1);
done();
});

it("My async Jest test", async () => {
expect(1).toEqual(1);
});

it("Test target function", () => {
const data = Buffer.from("a");
target.fuzzMe(data);
});
});
25 changes: 25 additions & 0 deletions examples/jest_typescript_integration/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Config } from "jest";

const config: Config = {
verbose: true,
projects: [
{
displayName: "Jest",
preset: "ts-jest",
},
{
displayName: {
name: "Jazzer.js",
color: "cyan",
},
preset: "ts-jest",
runner: "@jazzer.js/jest-runner",
testEnvironment: "node",
testMatch: ["<rootDir>/*.fuzz.[jt]s"],
},
],
coveragePathIgnorePatterns: ["/node_modules/", "/dist/"],
modulePathIgnorePatterns: ["/node_modules", "/dist/"],
};

export default config;
19 changes: 19 additions & 0 deletions examples/jest_typescript_integration/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "jest_typescript_integration",
"version": "1.0.0",
"description": "An example showing how Jazzer.js integrates with Jest and TypeScript",
"scripts": {
"build": "tsc",
"dryRun": "jest",
"fuzz": "JAZZER_FUZZ=1 jest --coverage",
"coverage": "jest --coverage"
},
"devDependencies": {
"@jazzer.js/jest-runner": "file:../../packages/jest-runner",
"@types/jest": "^29.4.0",
"jest": "^29.4.1",
"ts-jest": "^29.0.5",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
}
}
Loading