Skip to content

Commit b640254

Browse files
committed
feat(test-validation): add library support
- extract functions from AST for libraries (internal functions not in ABI) - add test coverage for library validation helpers - update exclusions for library-specific test patterns - add success message when all validations pass
1 parent 2e0d9ab commit b640254

File tree

3 files changed

+101
-9
lines changed

3 files changed

+101
-9
lines changed

packages/contracts-bedrock/scripts/checks/test-validation/exclusions.toml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ src_validation = [
2323
"test/cannon/MIPS64Memory.t.sol", # Tests external MIPS implementation
2424
"test/dispute/lib/LibClock.t.sol", # Tests library utilities
2525
"test/dispute/lib/LibGameId.t.sol", # Tests library utilities
26+
"test/libraries/DeployUtils.t.sol", # Tests library utilities - no direct src counterpart
2627
"test/setup/DeployVariations.t.sol", # Tests deployment variations
2728
"test/universal/BenchmarkTest.t.sol", # Performance benchmarking tests
2829
"test/universal/ExtendedPause.t.sol", # Tests extended functionality
@@ -56,6 +57,8 @@ contract_name_validation = [
5657
"test/L2/GasPriceOracle.t.sol", # Contains contracts not matching GasPriceOracle base name
5758
"test/universal/StandardBridge.t.sol", # Contains contracts not matching StandardBridge base name
5859
"test/L1/OPContractsManagerContractsContainer.t.sol", # Contains contracts not matching OPContractsManagerContractsContainer base name
60+
"test/libraries/Blueprint.t.sol", # Contains helper contracts (BlueprintHarness, ConstructorArgMock)
61+
"test/libraries/SafeCall.t.sol", # Contains helper contracts (SimpleSafeCaller)
5962
]
6063

6164
# PATHS EXCLUDED FROM FUNCTION NAME VALIDATION:
@@ -64,23 +67,21 @@ contract_name_validation = [
6467
# contract's ABI.
6568
#
6669
# Common reasons for exclusion:
67-
# - Libraries: Have different artifact structures that the validation system
68-
# doesn't currently support, making function name lookup impossible
6970
# - Internal/Private functions: Some contracts test internal functions that
7071
# aren't exposed in the public ABI, so they can't be validated
7172
# - Misspelled/Incorrect function names: Test contracts may have typos or
7273
# incorrect function names that don't match the actual source contract
7374
#
7475
# Resolving these issues requires either:
75-
# - Enhancing the validation system to support libraries and complex structures
76+
# - Enhancing the validation system to support complex structures
7677
# - Fixing misspelled function names in test contracts
7778
# - Restructuring tests to match actual function signatures
7879
function_name_validation = [
79-
"test/libraries", # Libraries have different artifact structure, unsupported
80-
"test/dispute/lib/LibPosition.t.sol", # Library testing - artifact structure issues
81-
"test/L1/ProxyAdminOwnedBase.t.sol", # Tests internal functions not in ABI
82-
"test/L1/SystemConfig.t.sol", # Tests internal functions not in ABI
83-
"test/safe/SafeSigners.t.sol", # Function name validation issues
80+
"test/L1/ProxyAdminOwnedBase.t.sol", # Tests internal functions not in ABI
81+
"test/L1/SystemConfig.t.sol", # Tests internal functions not in ABI
82+
"test/safe/SafeSigners.t.sol", # Function name validation issues
83+
"test/libraries/Predeploys.t.sol", # Function 'uncategorizedInterop' doesn't exist in library
84+
"test/libraries/TransientContext.t.sol", # Function 'reentrantAware' doesn't exist in library
8485
]
8586

8687
[excluded_tests]
@@ -91,4 +92,5 @@ contracts = [
9192
"OptimismPortal2_MigrateLiquidity_Test", # Interop tests hosted in the OptimismPortal2 test file
9293
"OptimismPortal2_MigrateToSuperRoots_Test", # Interop tests hosted in the OptimismPortal2 test file
9394
"OptimismPortal2_UpgradeInterop_Test", # Interop tests hosted in the OptimismPortal2 test file
95+
"Constants_Test", # Invalid naming pattern - doesn't specify function or Uncategorized
9496
]

packages/contracts-bedrock/scripts/checks/test-validation/main.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func main() {
3737
fmt.Printf("error: %v\n", err)
3838
os.Exit(1)
3939
}
40+
41+
fmt.Println("✅ All contract test validations passed")
4042
}
4143

4244
// Processes a single test artifact file and runs all validations
@@ -278,6 +280,36 @@ func findArtifactPath(contractFileName, contractName string) (string, error) {
278280
return files[0], nil
279281
}
280282

283+
// Checks if the artifact represents a library
284+
func isLibrary(artifact *solc.ForgeArtifact) bool {
285+
// Check the AST for ContractKind == "library"
286+
for _, node := range artifact.Ast.Nodes {
287+
if node.NodeType == "ContractDefinition" && node.ContractKind == "library" {
288+
return true
289+
}
290+
}
291+
return false
292+
}
293+
294+
// Extracts function names from the AST (for libraries with internal functions)
295+
func extractFunctionsFromAST(artifact *solc.ForgeArtifact) []string {
296+
var functions []string
297+
298+
// Navigate through AST to find function definitions
299+
for _, node := range artifact.Ast.Nodes {
300+
if node.NodeType == "ContractDefinition" {
301+
// Iterate through contract nodes to find functions
302+
for _, childNode := range node.Nodes {
303+
if childNode.NodeType == "FunctionDefinition" && childNode.Name != "" {
304+
functions = append(functions, childNode.Name)
305+
}
306+
}
307+
}
308+
}
309+
310+
return functions
311+
}
312+
281313
// Validates that a function exists in the source contract
282314
func checkFunctionExists(artifact *solc.ForgeArtifact, functionName string) bool {
283315
// Special functions always exist
@@ -309,7 +341,18 @@ func checkFunctionExists(artifact *solc.ForgeArtifact, functionName string) bool
309341
return false
310342
}
311343

312-
// Check if function exists in the ABI
344+
// Check if source is a library - use AST for internal functions
345+
if isLibrary(srcArtifact) {
346+
functions := extractFunctionsFromAST(srcArtifact)
347+
for _, fn := range functions {
348+
if strings.EqualFold(fn, functionName) {
349+
return true
350+
}
351+
}
352+
return false
353+
}
354+
355+
// For contracts, check if function exists in the ABI
313356
for _, method := range srcArtifact.Abi.Parsed.Methods {
314357
if strings.EqualFold(method.Name, functionName) {
315358
return true

packages/contracts-bedrock/scripts/checks/test-validation/main_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,53 @@ func TestFindArtifactPath(t *testing.T) {
369369
}
370370
}
371371

372+
func TestIsLibrary(t *testing.T) {
373+
library := &solc.ForgeArtifact{
374+
Ast: solc.Ast{
375+
Nodes: []solc.AstNode{
376+
{NodeType: "ContractDefinition", ContractKind: "library"},
377+
},
378+
},
379+
}
380+
contract := &solc.ForgeArtifact{
381+
Ast: solc.Ast{
382+
Nodes: []solc.AstNode{
383+
{NodeType: "ContractDefinition", ContractKind: "contract"},
384+
},
385+
},
386+
}
387+
if !isLibrary(library) {
388+
t.Error("library artifact should be detected as library")
389+
}
390+
if isLibrary(contract) {
391+
t.Error("contract artifact should not be detected as library")
392+
}
393+
}
394+
395+
func TestExtractFunctionsFromAST(t *testing.T) {
396+
artifact := &solc.ForgeArtifact{
397+
Ast: solc.Ast{
398+
Nodes: []solc.AstNode{
399+
{
400+
NodeType: "ContractDefinition",
401+
Nodes: []solc.AstNode{
402+
{NodeType: "FunctionDefinition", Name: "add"},
403+
{NodeType: "FunctionDefinition", Name: "subtract"},
404+
{NodeType: "VariableDeclaration", Name: "ignored"},
405+
},
406+
},
407+
},
408+
},
409+
}
410+
functions := extractFunctionsFromAST(artifact)
411+
if len(functions) != 2 {
412+
t.Errorf("expected 2 functions, got %d", len(functions))
413+
}
414+
if functions[0] != "add" || functions[1] != "subtract" {
415+
t.Errorf("unexpected function names: %v", functions)
416+
}
417+
}
418+
372419
func TestCheckFunctionExists(t *testing.T) {
373420
artifact := &solc.ForgeArtifact{Metadata: solc.ForgeCompilerMetadata{Settings: solc.CompilerSettings{CompilationTarget: map[string]string{"test/Contract.t.sol": "Contract_Test"}}}}
374421
if !checkFunctionExists(artifact, "constructor") {

0 commit comments

Comments
 (0)