@patchworkdev/common
Version:
Patchwork Development Kit
482 lines (481 loc) • 21.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const validateSchema_1 = require("./validateSchema");
const schemaFile = "../../schemas/patchwork-contract-config.schema.json";
const projectSchemaFile = "../../schemas/patchwork-project-config.schema.json";
describe("validateJsonSchema", () => {
const testDirectory = "./src/codegen/test_data";
const files = fs_1.default.readdirSync(testDirectory);
const jsonFiles = files.filter((file) => file.endsWith(".json"));
const solFiles = files.filter((file) => file.endsWith(".sol"));
const groupedFiles = jsonFiles.reduce((acc, jsonFile) => {
const baseName = path_1.default.basename(jsonFile, ".json");
acc[baseName] = {
json: path_1.default.join(testDirectory, jsonFile),
sol: path_1.default.join(testDirectory, baseName + ".sol"),
};
return acc;
}, {});
for (const [baseName, files] of Object.entries(groupedFiles)) {
if (solFiles.includes(baseName + ".sol")) {
it(`should validate ${baseName}.json successfully`, () => {
const jsonData = JSON.parse(fs_1.default.readFileSync(files.json, "utf8"));
const result = (0, validateSchema_1.validateSchema)(jsonData, schemaFile);
if (!result.isValid) {
console.error(`Validation errors for ${baseName}.json:`, result.errors);
}
expect(result.isValid).toBe(true);
});
}
}
});
describe("validateSchema", () => {
it("should fail validation for JSON without $schema", () => {
const invalidJson = {
scopeName: "test",
name: "AccountPatch",
symbol: "AP",
baseURI: "https://mything/my/",
schemaURI: "https://mything/my-metadata.json",
imageURI: "https://mything/my/{tokenID}.png",
features: ["accountpatch"],
fields: [
{
id: 1,
key: "name",
type: "char32",
description: "Name",
functionConfig: "all",
},
],
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors.some((error) => error.keyword === "required" &&
error.params.missingProperty === "$schema")).toBe(true);
});
it("should fail validation for JSON with incorrect $schema value", () => {
const invalidJson = {
$schema: "https://wrong-url.com/schema.json",
scopeName: "test",
name: "AccountPatch",
symbol: "AP",
baseURI: "https://mything/my/",
schemaURI: "https://mything/my-metadata.json",
imageURI: "https://mything/my/{tokenID}.png",
features: ["accountpatch"],
fields: [
{
id: 1,
key: "name",
type: "char32",
description: "Name",
functionConfig: "all",
},
],
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors.some((error) => error.keyword === "const" &&
error.message === "must be one of")).toBe(true);
});
it('should fail validation when multiple patch types are present', () => {
const invalidJson = {
"$schema": "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
"scopeName": "test",
"name": "Test",
"symbol": "TST",
"baseURI": "https://test.com/",
"schemaURI": "https://test.com/schema.json",
"imageURI": "https://test.com/image.png",
"fields": [],
"features": ["patch", "1155patch"]
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0].message).toBe('PATCH, 1155PATCH, and ACCOUNTPATCH are mutually exclusive.');
});
it("should fail validation when multiple fragment types are present", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "Test",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["fragmentmulti", "fragmentsingle"],
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0].message).toBe("FRAGMENTMULTI and FRAGMENTSINGLE are mutually exclusive.");
});
it("should fail validation when REVERSIBLE is present without a patch type", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "Test",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["reversible"],
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0].message).toBe("REVERSIBLE feature requires at least one of PATCH, 1155PATCH, or ACCOUNTPATCH to be present.");
});
it("should fail validation when WEAKREF is present without FRAGMENTSINGLE", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "Test",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["weakref"],
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0].message).toBe("WEAKREF feature requires FRAGMENTSINGLE feature");
});
it("should fail validation when DYNAMICREFLIBRARY is present without a dynamic array length literef field", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "Test",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["dynamicreflibrary"],
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0].message).toBe("DYNAMICREFLIBRARY feature requires a dynamic array length literef field");
});
it("should pass validation for a valid configuration", () => {
const validJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "Test",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["patch", "fragmentsingle"],
};
const result = (0, validateSchema_1.validateSchema)(validJson, schemaFile);
expect(result.isValid).toBe(true);
expect(result.errors).toHaveLength(0);
});
describe("name validation for contract configs", () => {
it("should fail validation when contract name starts with a number", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "4contract",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["patch"]
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, schemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0]).toEqual(expect.objectContaining({
keyword: "contractSchema",
message: "Contract name must not start with a number"
}));
});
it("should pass validation with valid contract name", () => {
const validJson = {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "test",
name: "Contract_123!@#",
symbol: "TST",
baseURI: "https://test.com/",
schemaURI: "https://test.com/schema.json",
imageURI: "https://test.com/image.png",
fields: [],
features: ["patch"]
};
const result = (0, validateSchema_1.validateSchema)(validJson, schemaFile);
expect(result.isValid).toBe(true);
expect(result.errors).toHaveLength(0);
});
});
describe("name validation for project configs", () => {
it("should fail validation when project name starts with a number", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "4project",
scopes: {},
contracts: {},
contractRelations: {}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0]).toEqual(expect.objectContaining({
keyword: "projectConfig",
message: "Project name must not start with a number"
}));
});
it("should pass validation when project name contains special characters", () => {
const validJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "project!@#",
scopes: {},
contracts: {},
contractRelations: {}
};
const result = (0, validateSchema_1.validateSchema)(validJson, projectSchemaFile);
expect(result.isValid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it("should pass validation with valid project name", () => {
const validJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "Project_123!@#",
scopes: {},
contracts: {},
contractRelations: {}
};
const result = (0, validateSchema_1.validateSchema)(validJson, projectSchemaFile);
expect(result.isValid).toBe(true);
expect(result.errors).toHaveLength(0);
});
});
});
describe("validateProjectConfigSchema", () => {
const testDirectory = "./src/codegen/test_data/project_configs";
const files = fs_1.default.readdirSync(testDirectory);
const jsonFiles = files.filter((file) => file.endsWith(".json"));
jsonFiles.forEach((jsonFile) => {
it(`should validate ${jsonFile} successfully`, () => {
const jsonData = JSON.parse(fs_1.default.readFileSync(path_1.default.join(testDirectory, jsonFile), "utf8"));
const result = (0, validateSchema_1.validateSchema)(jsonData, projectSchemaFile);
if (!result.isValid) {
console.error(`Validation errors for ${jsonFile}:`, result.errors);
}
expect(result.isValid).toBe(true);
});
});
it("should fail validation for project config without $schema", () => {
const invalidJson = {
name: "Invalid Project",
scopes: {},
contracts: {}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors).toHaveLength(1);
expect(result.errors[0]).toEqual(expect.objectContaining({
keyword: "required",
params: { missingProperty: '$schema' },
message: "must have required property '$schema'"
}));
});
it("should fail validation for project config with incorrect $schema value", () => {
const invalidJson = {
$schema: "https://wrong-url.com/schema.json",
name: "Invalid Project",
scopes: {},
contracts: {}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors).toHaveLength(1);
expect(result.errors[0]).toEqual(expect.objectContaining({
keyword: "const",
message: "must be one of",
params: {
allowedValues: [
"https://patchwork.dev/schema/patchwork-contract-config.schema.json",
"https://patchwork.dev/schema/patchwork-project-config.schema.json"
]
}
}));
});
it("should fail validation when a required field is missing", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "Invalid Project",
// missing 'scopes' field
contracts: {}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors.some((error) => error.keyword === "required" &&
error.params.missingProperty === "scopes")).toBe(true);
});
it("should fail validation when a scope has invalid properties", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "Invalid Project",
scopes: {
MyScope: {
name: "MyScope",
owner: "not-an-address",
whitelist: "not-a-boolean",
userAssign: "not-a-boolean",
userPatch: "not-a-boolean",
bankers: ["not-an-address"],
operators: ["not-an-address"],
mintConfigs: {
"not-an-address": {
flatFee: "not-a-number",
active: "not-a-boolean"
}
},
patchFees: {
"not-an-address": "not-a-number"
},
assignFees: {
"not-an-address": "not-a-number"
}
}
},
contracts: {}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors.length).toBeGreaterThan(0);
});
it("should fail validation when a contract config is invalid", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "Invalid Project",
scopes: {},
contracts: {
InvalidContract: {
config: {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
// missing required fields
},
fragments: []
}
}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors).toHaveLength(1);
expect(result.errors[0]).toEqual(expect.objectContaining({
keyword: "projectConfig"
}));
});
it("should pass validation for a valid project configuration", () => {
const validJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "Valid Project",
scopes: {
MyScope: {
name: "MyScope",
owner: "0x1234567890123456789012345678901234567890",
whitelist: true,
userAssign: false,
userPatch: false,
bankers: ["0x1234567890123456789012345678901234567890"],
operators: ["0x1234567890123456789012345678901234567890"],
mintConfigs: {
"0x1234567890123456789012345678901234567890": {
flatFee: 0,
active: true
}
},
patchFees: {
"0x1234567890123456789012345678901234567890": 0
},
assignFees: {
"0x1234567890123456789012345678901234567890": 0
}
}
},
contracts: {
ValidContract: {
config: {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "MyScope",
name: "ValidContract",
symbol: "VC",
baseURI: "https://example.com/",
schemaURI: "https://example.com/schema.json",
imageURI: "https://example.com/image.png",
features: ["patch"],
fields: [
{
id: 1,
key: "name",
type: "char32",
description: "Name",
functionConfig: "all"
}
]
},
fragments: []
}
}
};
const result = (0, validateSchema_1.validateSchema)(validJson, projectSchemaFile);
expect(result.isValid).toBe(true);
expect(result.errors).toHaveLength(0);
});
it("should fail validation when a contract config is invalid", () => {
const invalidJson = {
$schema: "https://patchwork.dev/schema/patchwork-project-config.schema.json",
name: "Invalid Project",
scopes: {
MyScope: {
name: "MyScope",
owner: "0x1234567890123456789012345678901234567890",
whitelist: true,
userAssign: false,
userPatch: false,
}
},
contracts: {
InvalidContract: {
config: {
$schema: "https://patchwork.dev/schema/patchwork-contract-config.schema.json",
scopeName: "MyScope",
name: "InvalidContract",
symbol: "IC",
baseURI: "https://example.com/",
schemaURI: "https://example.com/schema.json",
imageURI: "https://example.com/image.png",
features: ["invalidFeature"], // Invalid feature
fields: [
{
id: 1,
key: "name",
type: "invalidType", // Invalid field type
description: "Name",
functionConfig: "all"
}
]
},
fragments: []
}
},
contractRelations: {}
};
const result = (0, validateSchema_1.validateSchema)(invalidJson, projectSchemaFile);
expect(result.isValid).toBe(false);
expect(result.errors[0]).toEqual(expect.objectContaining({
keyword: "projectConfig",
message: expect.stringContaining("Feature not found: invalidFeature")
}));
});
});