Skip to content

Commit f04e695

Browse files
committed
fix: add title and sorting to the table
1 parent 65d6e9e commit f04e695

File tree

2 files changed

+142
-31
lines changed

2 files changed

+142
-31
lines changed

v-next/hardhat/src/internal/builtin-plugins/gas-analytics/gas-analytics-manager.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,18 @@ export class GasAnalyticsManagerImplementation implements GasAnalyticsManager {
210210
gasStatsByContract: GasStatsByContract,
211211
): string {
212212
const rows: TableItem[] = [];
213-
for (const [contractFqn, contractGasStats] of gasStatsByContract) {
213+
214+
if (gasStatsByContract.size > 0) {
215+
rows.push([chalk.bold("Gas Usage Statistics")]);
216+
rows.push(divider);
217+
}
218+
219+
// Sort contracts alphabetically for consistent output
220+
const sortedContracts = [...gasStatsByContract.entries()].sort(([a], [b]) =>
221+
a.localeCompare(b),
222+
);
223+
224+
for (const [contractFqn, contractGasStats] of sortedContracts) {
214225
rows.push([chalk.cyan.bold(getUserFqn(contractFqn))]);
215226
rows.push(divider);
216227

@@ -232,10 +243,15 @@ export class GasAnalyticsManagerImplementation implements GasAnalyticsManager {
232243
);
233244
}
234245

235-
for (const [
236-
functionDisplayName,
237-
gasStats,
238-
] of contractGasStats.functions) {
246+
// Sort functions by removing trailing ) and comparing alphabetically.
247+
// This ensures that overloaded functions with fewer params come first
248+
// (e.g., foo(uint256) comes before foo(uint256,uint256)). In other
249+
// scenarios, removing the trailing ) has no effect on the order.
250+
const sortedFunctions = [...contractGasStats.functions.entries()].sort(
251+
([a], [b]) => a.split(")")[0].localeCompare(b.split(")")[0]),
252+
);
253+
254+
for (const [functionDisplayName, gasStats] of sortedFunctions) {
239255
rows.push([
240256
functionDisplayName,
241257
`${gasStats.min}`,

v-next/hardhat/test/internal/builtin-plugins/gas-analytics/gas-analytics-manager.ts

Lines changed: 121 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -802,9 +802,38 @@ describe("gas-analytics-manager", () => {
802802
it("should generate a report", () => {
803803
const manager = new GasAnalyticsManagerImplementation(tmpDir);
804804
const gasStats = new Map();
805+
// Contracts are added in non-alphabetical order to test sorting
806+
gasStats.set("project/contracts/TokenA.sol:TokenA", {
807+
deployment: undefined,
808+
functions: new Map([
809+
// Functions are added in non-alphabetical order to test sorting
810+
[
811+
"transfer(address,uint256,bytes)",
812+
{
813+
min: 32000,
814+
max: 36000,
815+
avg: 34000,
816+
median: 34000,
817+
calls: 2,
818+
},
819+
],
820+
[
821+
"transfer(address,uint256)",
822+
{
823+
min: 22000,
824+
max: 28000,
825+
avg: 25000,
826+
median: 25000,
827+
calls: 2,
828+
},
829+
],
830+
]),
831+
});
832+
805833
gasStats.set("project/contracts/MyContract.sol:MyContract", {
806834
deployment: { gas: 500000, size: 2048 },
807835
functions: new Map([
836+
// Functions are added in non-alphabetical order to test sorting
808837
[
809838
"transfer",
810839
{
@@ -828,51 +857,117 @@ describe("gas-analytics-manager", () => {
828857
]),
829858
});
830859

831-
gasStats.set("project/contracts/TokenA.sol:TokenA", {
860+
const report = manager._generateGasStatsReport(gasStats);
861+
862+
const expectedReport = `
863+
| ${chalk.bold("Gas Usage Statistics")} | | | | | |
864+
| ----------------------------------- | --------------- | ------- | ------ | ----- | ------ |
865+
| ${chalk.cyan.bold("contracts/MyContract.sol:MyContract")} | | | | | |
866+
| ----------------------------------- | --------------- | ------- | ------ | ----- | ------ |
867+
| ${chalk.yellow("Deployment Cost")} | ${chalk.yellow("Deployment Size")} | | | | |
868+
| 500000 | 2048 | | | | |
869+
| ${chalk.yellow("Function name")} | ${chalk.yellow("Min")} | ${chalk.yellow("Average")} | ${chalk.yellow("Median")} | ${chalk.yellow("Max")} | ${chalk.yellow("#calls")} |
870+
| balanceOf | 15000 | 15000 | 15000 | 15000 | 1 |
871+
| transfer | 20000 | 25000 | 25000 | 30000 | 3 |
872+
| | | | | | |
873+
| ${chalk.cyan.bold("contracts/TokenA.sol:TokenA")} | | | | | |
874+
| ----------------------------------- | --------------- | ------- | ------ | ----- | ------ |
875+
| ${chalk.yellow("Function name")} | ${chalk.yellow("Min")} | ${chalk.yellow("Average")} | ${chalk.yellow("Median")} | ${chalk.yellow("Max")} | ${chalk.yellow("#calls")} |
876+
| transfer(address,uint256) | 22000 | 25000 | 25000 | 28000 | 2 |
877+
| transfer(address,uint256,bytes) | 32000 | 34000 | 34000 | 36000 | 2 |
878+
`.trim();
879+
880+
assert.equal(report, expectedReport);
881+
});
882+
883+
it("should sort overloads with same parameter count correctly", () => {
884+
const manager = new GasAnalyticsManagerImplementation(tmpDir);
885+
const gasStats = new Map();
886+
gasStats.set("project/contracts/TestContract.sol:TestContract", {
832887
deployment: undefined,
833888
functions: new Map([
834889
[
835890
"transfer(address,uint256)",
836891
{
837-
min: 22000,
838-
max: 28000,
892+
min: 25000,
893+
max: 25000,
839894
avg: 25000,
840895
median: 25000,
841-
calls: 2,
896+
calls: 1,
842897
},
843898
],
844899
[
845-
"transfer(address,uint256,bytes)",
900+
"transfer(address,bytes32)",
846901
{
847-
min: 32000,
848-
max: 36000,
849-
avg: 34000,
850-
median: 34000,
851-
calls: 2,
902+
min: 23000,
903+
max: 23000,
904+
avg: 23000,
905+
median: 23000,
906+
calls: 1,
852907
},
853908
],
854909
]),
855910
});
856911

857912
const report = manager._generateGasStatsReport(gasStats);
858913

859-
const expectedReport = `
860-
| ${chalk.cyan.bold("contracts/MyContract.sol:MyContract")} | | | | | |
861-
| ----------------------------------- | --------------- | ------- | ------ | ----- | ------ |
862-
| ${chalk.yellow("Deployment Cost")} | ${chalk.yellow("Deployment Size")} | | | | |
863-
| 500000 | 2048 | | | | |
864-
| ${chalk.yellow("Function name")} | ${chalk.yellow("Min")} | ${chalk.yellow("Average")} | ${chalk.yellow("Median")} | ${chalk.yellow("Max")} | ${chalk.yellow("#calls")} |
865-
| transfer | 20000 | 25000 | 25000 | 30000 | 3 |
866-
| balanceOf | 15000 | 15000 | 15000 | 15000 | 1 |
867-
| | | | | | |
868-
| ${chalk.cyan.bold("contracts/TokenA.sol:TokenA")} | | | | | |
869-
| ----------------------------------- | --------------- | ------- | ------ | ----- | ------ |
870-
| ${chalk.yellow("Function name")} | ${chalk.yellow("Min")} | ${chalk.yellow("Average")} | ${chalk.yellow("Median")} | ${chalk.yellow("Max")} | ${chalk.yellow("#calls")} |
871-
| transfer(address,uint256) | 22000 | 25000 | 25000 | 28000 | 2 |
872-
| transfer(address,uint256,bytes) | 32000 | 34000 | 34000 | 36000 | 2 |
873-
`.trim();
914+
const lines = report.split("\n");
915+
const transferBytes32Line = lines.findIndex((line) =>
916+
line.includes("transfer(address,bytes32)"),
917+
);
918+
const transferUint256Line = lines.findIndex((line) =>
919+
line.includes("transfer(address,uint256)"),
920+
);
874921

875-
assert.equal(report, expectedReport);
922+
assert.ok(
923+
transferBytes32Line < transferUint256Line,
924+
"transfer(address,bytes32) should come before transfer(address,uint256)",
925+
);
926+
});
927+
928+
it("should sort overloads with different parameter counts correctly", () => {
929+
const manager = new GasAnalyticsManagerImplementation(tmpDir);
930+
const gasStats = new Map();
931+
gasStats.set("project/contracts/TestContract.sol:TestContract", {
932+
deployment: undefined,
933+
functions: new Map([
934+
[
935+
"mint(uint256,bytes)",
936+
{
937+
min: 35000,
938+
max: 35000,
939+
avg: 35000,
940+
median: 35000,
941+
calls: 1,
942+
},
943+
],
944+
[
945+
"mint(uint256)",
946+
{
947+
min: 25000,
948+
max: 25000,
949+
avg: 25000,
950+
median: 25000,
951+
calls: 1,
952+
},
953+
],
954+
]),
955+
});
956+
957+
const report = manager._generateGasStatsReport(gasStats);
958+
959+
const lines = report.split("\n");
960+
const mintUint256Line = lines.findIndex((line) =>
961+
line.includes("mint(uint256)"),
962+
);
963+
const mintBytesLine = lines.findIndex((line) =>
964+
line.includes("mint(uint256,bytes)"),
965+
);
966+
967+
assert.ok(
968+
mintUint256Line < mintBytesLine,
969+
"mint(uint256) should come before mint(uint256,bytes)",
970+
);
876971
});
877972
});
878973
});

0 commit comments

Comments
 (0)