UNPKG

@patchworkdev/common

Version:

Patchwork Development Kit

213 lines (212 loc) 9.85 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const child_process_1 = require("child_process"); const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const types_1 = require("../../types"); const contractSchema_1 = require("../contractSchema"); const mainContractGen_1 = require("../mainContractGen"); const userContractGen_1 = require("../userContractGen"); function generateField(features) { const fields = [ { id: 1, key: "single_char_field", type: "char16", description: "A single char field", }, ]; // Special case for DYNAMICREFLIBRARY feature if (features.includes(types_1.Feature.DYNAMICREFLIBRARY)) { fields.push({ id: fields.length + 1, key: 'dynamic_literef', type: 'literef', arrayLength: 0, description: 'Dynamic literef array for DYNAMICREFLIBRARY feature', }); } return fields; } function generateFeaturePermutations() { const baseFeatures = [types_1.Feature.MINTABLE, types_1.Feature.LITEREF]; const patchTypes = [types_1.Feature.PATCH, types_1.Feature["1155PATCH"], types_1.Feature.ACCOUNTPATCH]; const fragmentTypes = [types_1.Feature.FRAGMENTMULTI, types_1.Feature.FRAGMENTSINGLE]; let permutations = [[]]; // Add base features baseFeatures.forEach((feature) => { permutations = permutations.flatMap((perm) => [perm, [...perm, feature]]); }); // Add patch types (mutually exclusive) permutations = permutations.flatMap((perm) => [ perm, ...patchTypes.map((patchType) => [...perm, patchType]), ]); // Add fragment types (mutually exclusive) permutations = permutations.flatMap((perm) => [ perm, ...fragmentTypes.map((fragmentType) => [...perm, fragmentType]), ]); // Add REVERSIBLE only to permutations with a patch type permutations = permutations.flatMap((perm) => patchTypes.some((patch) => perm.includes(patch)) ? [perm, [...perm, types_1.Feature.REVERSIBLE]] : [perm]); // Add WEAKREF only to permutations with FRAGMENTSINGLE permutations = permutations.flatMap((perm) => perm.includes(types_1.Feature.FRAGMENTSINGLE) ? [perm, [...perm, types_1.Feature.WEAKREF]] : [perm]); // Add DYNAMICREFLIBRARY only to permutations with LITEREF permutations = permutations.flatMap((perm) => perm.includes(types_1.Feature.LITEREF) ? [perm, [...perm, types_1.Feature.DYNAMICREFLIBRARY]] : [perm]); return permutations; } function generateContractSchemaPermutations() { const baseConfig = { scopeName: "TestScope", name: "TestContract", symbol: "TST", baseURI: "https://example.com/", schemaURI: "https://example.com/schema", imageURI: "https://example.com/image", fields: [], features: [], fragments: [] }; const featurePermutations = generateFeaturePermutations(); return featurePermutations.map((features) => ({ ...baseConfig, fields: generateField(features), features, })); } function removeDirectoryRecursive(dirPath) { if (fs_1.default.existsSync(dirPath)) { fs_1.default.readdirSync(dirPath).forEach((file) => { const curPath = path_1.default.join(dirPath, file); if (fs_1.default.lstatSync(curPath).isDirectory()) { // Recursive call for directories removeDirectoryRecursive(curPath); } else { // Delete file fs_1.default.unlinkSync(curPath); } }); fs_1.default.rmdirSync(dirPath); } } describe("Generate and Build Contract Schema Permutations", () => { const outputDir = path_1.default.join(__dirname, "generated_contracts"); const schemaNoVerifyDir = path_1.default.join(__dirname, "schema_noverify"); const schemaNoBuildDir = path_1.default.join(__dirname, "schema_nobuild"); beforeAll(() => { // Create directories if they don't exist [outputDir, schemaNoVerifyDir, schemaNoBuildDir].forEach(dir => { if (!fs_1.default.existsSync(dir)) { fs_1.default.mkdirSync(dir, { recursive: true }); } }); // Clear contents of schema_noverify and schema_nobuild [schemaNoVerifyDir, schemaNoBuildDir].forEach(dir => { removeDirectoryRecursive(dir); fs_1.default.mkdirSync(dir); }); // Clear contents of generated_contracts, preserving remappings.txt and foundry.toml fs_1.default.readdirSync(outputDir).forEach(file => { const filePath = path_1.default.join(outputDir, file); if (file !== 'remappings.txt' && file !== 'foundry.toml') { if (fs_1.default.lstatSync(filePath).isDirectory()) { removeDirectoryRecursive(filePath); } else { fs_1.default.unlinkSync(filePath); } } }); }); it("should generate, save, and build all contract schema permutations", async () => { console.log("Generating contract schema permutations..."); const permutations = generateContractSchemaPermutations(); const mainContractGen = new mainContractGen_1.MainContractGen(); const userContractGen = new userContractGen_1.UserContractGen(); let errors = []; for (let index = 0; index < permutations.length; index++) { // if (index > 1) { // break; // } const config = permutations[index]; console.log(`Processing permutation ${index}:`, config); const schema = new contractSchema_1.ContractSchemaImpl(config); try { schema.validate(); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Schema validation failed for contract ${index}:`, errorMessage); fs_1.default.writeFileSync(path_1.default.join(schemaNoVerifyDir, `schema_${index}.json`), JSON.stringify(config, null, 2)); errors.push(`Schema validation failed for contract ${index}: ${errorMessage}`); continue; // Skip to the next permutation } try { const mainCode = mainContractGen.gen(schema); const userCode = userContractGen.gen(schema); const mainFileName = path_1.default.join(outputDir, `TestContractGenerated.sol`); const userFileName = path_1.default.join(outputDir, `TestContract.sol`); fs_1.default.writeFileSync(mainFileName, mainCode); fs_1.default.writeFileSync(userFileName, userCode); console.log(`Generated contract ${index}`); // Call forge build await new Promise((resolve, reject) => { (0, child_process_1.exec)('forge build', { cwd: outputDir }, (error, stdout, stderr) => { if (error) { console.error(`forge build failed for contract ${index}:`); console.error(error); fs_1.default.writeFileSync(path_1.default.join(schemaNoBuildDir, `schema_${index}.json`), JSON.stringify(config, null, 2)); errors.push(`forge build failed for contract ${index}: ${stderr}`); resolve(); // Resolve even on error to continue processing } else { console.log(`Successfully built contract ${index}`); resolve(); } }); }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Error in contract ${index}:`, errorMessage); errors.push(`Error in contract ${index}: ${errorMessage}`); } finally { // Clean up .sol files after each attempt const mainFileName = path_1.default.join(outputDir, `TestContractGenerated.sol`); const userFileName = path_1.default.join(outputDir, `TestContract.sol`); if (fs_1.default.existsSync(mainFileName)) fs_1.default.unlinkSync(mainFileName); if (fs_1.default.existsSync(userFileName)) fs_1.default.unlinkSync(userFileName); } // Add a small delay between iterations to allow for any pending I/O operations await new Promise(resolve => setTimeout(resolve, 100)); } console.log(`Total permutations processed: ${permutations.length}`); console.log(`Total errors encountered: ${errors.length}`); if (errors.length > 0) { console.error("Errors encountered during processing:"); errors.forEach((error, index) => { console.error(`${index + 1}: ${error}`); }); throw new Error(`${errors.length} errors encountered during processing`); } expect(permutations.length).toBeGreaterThan(0); }); afterAll(() => { // Clean up after all tests removeDirectoryRecursive(path_1.default.join(outputDir, 'out')); removeDirectoryRecursive(path_1.default.join(outputDir, 'cache')); }); });