Skip to content

Commit

Permalink
feat: add missing functions in abstract contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
agusduha committed Apr 5, 2024
1 parent edb4c47 commit 8522001
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 2 deletions.
17 changes: 17 additions & 0 deletions solidity/contracts/utils/ContractBAbstract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pragma solidity ^0.8.0;

import {IContractBAbstract} from '../../interfaces/IContractBAbstract.sol';
import {IContractB2Abstract} from '../../interfaces/IContractB2Abstract.sol';

abstract contract ContractBAbstract is IContractBAbstract, IContractB2Abstract {
uint256 public uintVariable;

constructor(uint256 _uintVariable) {
uintVariable = _uintVariable;
}

function setVariablesA(uint256 _newValue) public returns (bool _result) {
uintVariable = _newValue;
_result = true;
}
}
5 changes: 5 additions & 0 deletions solidity/interfaces/IContractB2Abstract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma solidity ^0.8.0;

interface IContractB2Abstract {
function undefinedInterfaceFunc2(uint256 _someNumber) external returns (bool _result);
}
5 changes: 5 additions & 0 deletions solidity/interfaces/IContractBAbstract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma solidity ^0.8.0;

interface IContractBAbstract {
function undefinedInterfaceFunc(uint256 _someNumber) external returns (bool _result);
}
5 changes: 5 additions & 0 deletions src/smock-foundry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getSourceUnits,
smockableNode,
compileSolidityFilesFoundry,
renderAbstractUnimplementedFunctions,
} from './utils';
import path from 'path';
import { ensureDir } from 'fs-extra';
Expand Down Expand Up @@ -44,6 +45,10 @@ export async function generateMockContracts(
// Libraries are not mocked
if (contract.kind === 'library') continue;

if (contract.abstract) {
mockContent += await renderAbstractUnimplementedFunctions(contract);
}

for (const node of contract.children) {
if (!smockableNode(node)) continue;
mockContent += await renderNodeMock(node);
Expand Down
42 changes: 40 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import Handlebars from 'handlebars';
import path from 'path';
import { glob } from 'fast-glob';
import { VariableDeclaration, FunctionDefinition, ImportDirective, ASTNode, ASTKind, ASTReader, SourceUnit, compileSol } from 'solc-typed-ast';
import {
VariableDeclaration,
FunctionDefinition,
ImportDirective,
ASTNode,
ASTKind,
ASTReader,
SourceUnit,
compileSol,
ContractDefinition,
} from 'solc-typed-ast';
import { userDefinedTypes, explicitTypes } from './types';
import { readFileSync } from 'fs'; // TODO: Replace with fs/promises
import { ensureDir, emptyDir } from 'fs-extra';
Expand Down Expand Up @@ -261,7 +271,8 @@ export async function getSourceUnits(rootPath: string, contractsDirectories: str
includePath: [rootPath],
});

const sourceUnits = new ASTReader().read(compiledFiles.data, ASTKind.Any, compiledFiles.files)
const sourceUnits = new ASTReader()
.read(compiledFiles.data, ASTKind.Any, compiledFiles.files)
// Skip source units that are not in the contracts directories
.filter((sourceUnit) => contractsDirectories.some((directory) => sourceUnit.absolutePath.includes(directory)));

Expand All @@ -281,3 +292,30 @@ export function smockableNode(node: ASTNode): boolean {

return true;
}

/**
* Renders the abstract functions that are not implemented in the current contract
* @param contract The contract to render the abstract functions from
* @returns The content of the functions
*/
export async function renderAbstractUnimplementedFunctions(contract: ContractDefinition): Promise<string> {
let content = '';

if (contract.vLinearizedBaseContracts.length > 1) {
const functions = contract.vFunctions;

// Skip the first contract, which is the current contract
for (let i = 1; i < contract.vLinearizedBaseContracts.length; i++) {
const base = contract.vLinearizedBaseContracts[i];

for (const baseFunction of base.vFunctions) {
// If the function is not implemented in the current contract, render it
if (!functions.some((func) => func.raw?.functionSelector === baseFunction.raw?.functionSelector)) {
content += await renderNodeMock(baseFunction);
}
}
}
}

return content;
}

0 comments on commit 8522001

Please sign in to comment.