Skip to content

Commit

Permalink
Add support for custom manifest file
Browse files Browse the repository at this point in the history
This commit allows Rendezvous users to design a custom manifest file for each
fuzzed contract. This also allows for testing doubles. The custom manifest file
should be named `Clarinet-<contract-name>.toml`.
  • Loading branch information
BowTiedRadone committed Jan 31, 2025
1 parent a9ea925 commit 2bdfed1
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 9 deletions.
16 changes: 15 additions & 1 deletion app.tests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { red } from "ansicolor";
import { main } from "./app";
import { getManifestFileName, main } from "./app";
import { version } from "./package.json";

describe("Command-line arguments handling", () => {
Expand Down Expand Up @@ -366,3 +366,17 @@ describe("Command-line arguments handling", () => {
}
);
});

describe("Custom manifest detection", () => {
it("returns the default manifest file name for the example project", () => {
// Arrange
const manifestDir = "example";
const targetContractName = "counter";

// Act
const actual = getManifestFileName(manifestDir, targetContractName);

// Assert
expect(actual).toBe("Clarinet.toml");
});
});
42 changes: 38 additions & 4 deletions app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env node
import { join } from "path";
import { join, resolve } from "path";
import { EventEmitter } from "events";
import { checkProperties } from "./property";
import { checkInvariants } from "./invariant";
Expand All @@ -11,11 +11,35 @@ import {
import { issueFirstClassCitizenship } from "./citizen";
import { version } from "./package.json";
import { red } from "ansicolor";
import { existsSync } from "fs";

const logger = (log: string, logLevel: "log" | "error" | "info" = "log") => {
console[logLevel](log);
};

/**
* Gets the manifest file name for a Clarinet project.
* If a custom manifest exists (`Clarinet-<contract-name>.toml`), it is used.
* Otherwise, the default `Clarinet.toml` is returned.
* @param manifestDir The relative path to the Clarinet project directory.
* @param targetContractName The target contract name.
* @returns The manifest file name.
*/
export const getManifestFileName = (
manifestDir: string,
targetContractName: string
) => {
const isCustomManifest = existsSync(
resolve(manifestDir, `Clarinet-${targetContractName}.toml`)
);

if (isCustomManifest) {
return `Clarinet-${targetContractName}.toml`;
}

return "Clarinet.toml";
};

const helpMessage = `
rv v${version}
Expand Down Expand Up @@ -90,8 +114,14 @@ export async function main() {
return;
}

/** The relative path to `Clarinet.toml`. */
const manifestPath = join(manifestDir, "Clarinet.toml");
/**
* The relative path to the manifest file, either `Clarinet.toml` or
* `Clarinet-<contract-name>.toml`. If the latter exists, it is used.
*/
const manifestPath = join(
manifestDir,
getManifestFileName(manifestDir, sutContractName)
);
radio.emit("logMessage", `Using manifest path: ${manifestPath}`);
radio.emit("logMessage", `Target contract: ${sutContractName}`);

Expand All @@ -110,7 +140,11 @@ export async function main() {
radio.emit("logMessage", `Using runs: ${runs}`);
}

const simnet = await issueFirstClassCitizenship(manifestDir, sutContractName);
const simnet = await issueFirstClassCitizenship(
manifestDir,
manifestPath,
sutContractName
);

/**
* The list of contract IDs for the SUT contract names, as per the simnet.
Expand Down
7 changes: 6 additions & 1 deletion citizen.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { join } from "path";
import { cpSync, existsSync, mkdtempSync, readFileSync, rmSync } from "fs";
import { tmpdir } from "os";
import yaml from "yaml";
import { getManifestFileName } from "./app";

describe("Simnet deployment plan operations", () => {
const manifestDir = "example";
Expand Down Expand Up @@ -337,7 +338,11 @@ describe("Simnet deployment plan operations", () => {
cpSync(manifestDir, tempDir, { recursive: true });

// Exercise
const firstClassSimnet = await issueFirstClassCitizenship(tempDir, "cargo");
const firstClassSimnet = await issueFirstClassCitizenship(
tempDir,
join(tempDir, getManifestFileName(tempDir, "cargo")),
"cargo"
);
const actual = firstClassSimnet.getContractSource("cargo");

// Verify
Expand Down
4 changes: 2 additions & 2 deletions citizen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ import {
* to the simnet.
*
* @param manifestDir The relative path to the manifest directory.
* @param manifestPath The absolute path to the manifest file.
* @param sutContractName The target contract name.
* @returns The initialized simnet instance with all contracts deployed, with
* the test contract treated as a first-class citizen of the target contract.
*/
export const issueFirstClassCitizenship = async (
manifestDir: string,
manifestPath: string,
sutContractName: string
): Promise<Simnet> => {
const manifestPath = join(manifestDir, "Clarinet.toml");

// Initialize the simnet, to generate the simnet plan and instance. The empty
// session will be set up, and contracts will be deployed in the correct
// order based on the simnet plan a few lines below.
Expand Down
7 changes: 6 additions & 1 deletion invariant.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { join } from "path";
import { issueFirstClassCitizenship } from "./citizen";
import { Cl } from "@stacks/transactions";
import { getManifestFileName } from "./app";

describe("Simnet contracts operations", () => {
it("correctly initializes the local context for a given functions map", async () => {
Expand Down Expand Up @@ -39,7 +40,11 @@ describe("Simnet contracts operations", () => {

it("correctly initializes the Clarity context", async () => {
// Arrange
const simnet = await issueFirstClassCitizenship("example", "counter");
const simnet = await issueFirstClassCitizenship(
"example",
join("example", getManifestFileName("example", "counter")),
"counter"
);

const rendezvousList = Array.from(
getSimnetDeployerContractsInterfaces(simnet).keys()
Expand Down

0 comments on commit 2bdfed1

Please sign in to comment.