Skip to content

Commit

Permalink
feat(tests): Improve test suite (nowarp#184)
Browse files Browse the repository at this point in the history
* Run tests for detectors separately, without checking their dumps (see: nowarp#162)
* Increase the number of test workers and timeouts
* Write DumpImport tests
* Merge tests with syntax constructions

Closes nowarp#162
  • Loading branch information
jubnzv authored Oct 17, 2024
1 parent 5668d62 commit 930a429
Show file tree
Hide file tree
Showing 191 changed files with 2,306 additions and 6,918 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ jobs:

- name: Validate expected Mermaid diagrams
run: |
for file in test/good/*.mmd; do
for file in test/all/*.mmd; do
mmdc -i "$file" -o /tmp/skip.svg || exit 1
done
- name: Validate expected Graphviz files
run: |
for file in test/good/*.dot; do
for file in test/all/*.dot; do
dot -Tdot "$file" -o /dev/null || exit 1
done
Expand Down
20 changes: 12 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,18 @@ tags
docs

# Generated test artifacts
test/good/**/*.config.json
test/good/**/*.json
test/good/**/*.dot
test/good/**/*.mmd
test/good/**/*.actual.out
!test/good/**/*.cfg.json
!test/good/**/*.cfg.dot
!test/good/**/*.cfg.mmd
test/all/**/*.config.json
test/all/**/*.json
test/all/**/*.dot
test/all/**/*.mmd
test/all/**/*.actual.out
test/detectors/**/*.actual.out
!test/all/**/*.cfg.json
!test/all/**/*.cfg.dot
!test/all/**/*.cfg.mmd
!test/all/**/*.imports.json
!test/all/**/*.imports.dot
!test/all/**/*.imports.mmd

# Generated code
src/version-info.ts
4 changes: 2 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test/good
test/bad
test/detectors
test/all
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `CellOverflow` detector: PR [#177](https://github.com/nowarp/misti/pulls/177)
- Import Graph: PR [#180](https://github.com/nowarp/misti/pulls/180)

### Changed
- Improved and optimized the test suite: PR [#184](https://github.com/nowarp/misti/pull/184)

## [0.4.2] - 2024-10-12

### Fixed
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ module.exports = {
preset : "ts-jest",
testEnvironment : "node",
testPathIgnorePatterns : [ "/node_modules/", "/dist/" ],
maxWorkers : 1,
maxWorkers: "50%",
testTimeout: 15000,
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
* }
* ```
*/
export class UnboundLoops extends SouffleDetector {
export class UnboundLoop extends SouffleDetector {
severity = Severity.HIGH;

async check(cu: CompilationUnit): Promise<MistiTactWarning[]> {
Expand Down
6 changes: 3 additions & 3 deletions src/detectors/detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ export const BuiltInDetectors: Record<string, DetectorEntry> = {
),
enabledByDefault: true,
},
UnboundLoops: {
UnboundLoop: {
loader: (ctx: MistiContext) =>
import("./builtin/unboundLoops").then(
(module) => new module.UnboundLoops(ctx),
import("./builtin/unboundLoop").then(
(module) => new module.UnboundLoop(ctx),
),
enabledByDefault: true,
},
Expand Down
9 changes: 8 additions & 1 deletion src/internals/ir/builders/imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,17 @@ export class ImportGraphBuilder {
const fileContent = fs.readFileSync(filePath, "utf8");
const imports = Parser.parseImports(fileContent, filePath, "user");

// Use the actual path when working in single contract mode, not the temporary directory.
let importPath = filePath;
if (this.ctx.tactPath && this.ctx.tactPath.kind === "contract") {
const tempDir = path.dirname(this.ctx.tactPath.tempConfigPath);
importPath = path.relative(tempDir, filePath);
}

const node = new ImportNode(
this.generateNodeName(filePath),
definedInStdlib(this.ctx, filePath) ? "stdlib" : "user",
filePath,
importPath,
this.determineLanguage(filePath),
this.hasContract(fileContent),
);
Expand Down
10 changes: 10 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Here's the updated text with the grammar fixed:

# Tests

## Structure

The following directories contain contracts:

- `all` – contains various contracts for which most tests are executed. You should not add new tests there if possible, since these execution is quite slow.
- `detectors` – contains contracts named after each detector. See `builtinDetectors.spec.ts` to understand how it is used.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[MEDIUM] NeverAccessedVariables: Constant Unused is never used
test/good/imports-1/constants.tact:2:1:
test/all/imports-1/constants.tact:2:1:
1 | const Used: Int = 42;
> 2 | const Unused: Int = 19;
^
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[MEDIUM] NeverAccessedVariables: Constant UNUSED is never used
test/good/imports-2/constants.tact:3:1:
test/all/imports-2/constants.tact:3:1:
2 | const USED_IN_SECOND: Int = 2;
> 3 | const UNUSED: Int = 3;
^
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
141 changes: 141 additions & 0 deletions test/all/sample-jetton.expected.cfg.dot
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
digraph "sample-jetton" {
node [shape=box];
subgraph "cluster_SampleJetton__init_1905" {
label="SampleJetton__init_1905";
"SampleJetton__init_1905_68" [label="self.totalSupply = 0"];
"SampleJetton__init_1905_69" [label="self.max_supply = max_supply"];
"SampleJetton__init_1905_70" [label="self.owner = owner"];
"SampleJetton__init_1905_71" [label="self.mintable = true"];
"SampleJetton__init_1905_72" [label="self.content = content",style=filled,fillcolor="#66A7DB"];
"SampleJetton__init_1905_68" -> "SampleJetton__init_1905_69";
"SampleJetton__init_1905_69" -> "SampleJetton__init_1905_70";
"SampleJetton__init_1905_70" -> "SampleJetton__init_1905_71";
"SampleJetton__init_1905_71" -> "SampleJetton__init_1905_72";
}
subgraph "cluster_SampleJetton__receive_internal_simple_1855" {
label="SampleJetton__receive_internal_simple_1855";
"SampleJetton__receive_internal_simple_1855_73" [label="let ctx: Context = context()"];
"SampleJetton__receive_internal_simple_1855_74" [label="require(ctx.sender == self.owner, \"Not Owner\")"];
"SampleJetton__receive_internal_simple_1855_75" [label="require(self.mintable, \"Can't Mint Anymore\")"];
"SampleJetton__receive_internal_simple_1855_76" [label="self.mint(msg.receiver, msg.amount, self.owner)",style=filled,fillcolor="#66A7DB"];
"SampleJetton__receive_internal_simple_1855_73" -> "SampleJetton__receive_internal_simple_1855_74";
"SampleJetton__receive_internal_simple_1855_74" -> "SampleJetton__receive_internal_simple_1855_75";
"SampleJetton__receive_internal_simple_1855_75" -> "SampleJetton__receive_internal_simple_1855_76";
}
subgraph "cluster_SampleJetton__receive_internal_comment_1880_Mint: 100" {
label="SampleJetton__receive_internal_comment_1880_Mint: 100";
"SampleJetton__receive_internal_comment_1880_Mint: 100_77" [label="let ctx: Context = context()"];
"SampleJetton__receive_internal_comment_1880_Mint: 100_78" [label="require(self.mintable, \"Can't Mint Anymore\")"];
"SampleJetton__receive_internal_comment_1880_Mint: 100_79" [label="self.mint(ctx.sender, 100, self.owner)",style=filled,fillcolor="#66A7DB"];
"SampleJetton__receive_internal_comment_1880_Mint: 100_77" -> "SampleJetton__receive_internal_comment_1880_Mint: 100_78";
"SampleJetton__receive_internal_comment_1880_Mint: 100_78" -> "SampleJetton__receive_internal_comment_1880_Mint: 100_79";
}
subgraph "cluster_SampleJetton__receive_internal_comment_1903_Owner: MintClose" {
label="SampleJetton__receive_internal_comment_1903_Owner: MintClose";
"SampleJetton__receive_internal_comment_1903_Owner: MintClose_80" [label="let ctx: Context = context()"];
"SampleJetton__receive_internal_comment_1903_Owner: MintClose_81" [label="require(ctx.sender == self.owner, \"Not Owner\")"];
"SampleJetton__receive_internal_comment_1903_Owner: MintClose_82" [label="self.mintable = false",style=filled,fillcolor="#66A7DB"];
"SampleJetton__receive_internal_comment_1903_Owner: MintClose_80" -> "SampleJetton__receive_internal_comment_1903_Owner: MintClose_81";
"SampleJetton__receive_internal_comment_1903_Owner: MintClose_81" -> "SampleJetton__receive_internal_comment_1903_Owner: MintClose_82";
}
subgraph "cluster_JettonDefaultWallet__init_2908" {
label="JettonDefaultWallet__init_2908";
"JettonDefaultWallet__init_2908_83" [label="self.balance = 0"];
"JettonDefaultWallet__init_2908_84" [label="self.owner = owner"];
"JettonDefaultWallet__init_2908_85" [label="self.master = master",style=filled,fillcolor="#66A7DB"];
"JettonDefaultWallet__init_2908_83" -> "JettonDefaultWallet__init_2908_84";
"JettonDefaultWallet__init_2908_84" -> "JettonDefaultWallet__init_2908_85";
}
subgraph "cluster_JettonDefaultWallet__receive_internal_simple_2515" {
label="JettonDefaultWallet__receive_internal_simple_2515";
"JettonDefaultWallet__receive_internal_simple_2515_86" [label="let ctx: Context = context()"];
"JettonDefaultWallet__receive_internal_simple_2515_87" [label="require(ctx.sender == self.owner, \"Invalid sender\")"];
"JettonDefaultWallet__receive_internal_simple_2515_88" [label="let fwdFee: Int = ctx.readForwardFee() + ctx.readForwardFee()"];
"JettonDefaultWallet__receive_internal_simple_2515_89" [label="let final: Int = 2 * self.gasConsumption + self.minTonsForStorage + fwdFee"];
"JettonDefaultWallet__receive_internal_simple_2515_90" [label="require(ctx.value > min(final, ton(\"0.01\")), \"Invalid value!!\")"];
"JettonDefaultWallet__receive_internal_simple_2515_91" [label="self.balance = self.balance - msg.amount"];
"JettonDefaultWallet__receive_internal_simple_2515_92" [label="require(self.balance >= 0, \"Invalid balance\")"];
"JettonDefaultWallet__receive_internal_simple_2515_93" [label="let init: StateInit = initOf JettonDefaultWallet(self.master, msg.destination)"];
"JettonDefaultWallet__receive_internal_simple_2515_94" [label="let walletAddress: Address = contractAddress(init)"];
"JettonDefaultWallet__receive_internal_simple_2515_95" [label="send(SendParameters{to: walletAddress, value: 0, mode: SendRemainingValue, bounce: false, body: TokenTransferInternal{queryId: msg.queryId, amount: msg.amount, from: self.owner, response_destination: msg.response_destination, forward_ton_amount: msg.forward_ton_amount, forward_payload: msg.forward_payload}.toCell(), code: init.code, data: init.data})",style=filled,fillcolor="#66A7DB"];
"JettonDefaultWallet__receive_internal_simple_2515_86" -> "JettonDefaultWallet__receive_internal_simple_2515_87";
"JettonDefaultWallet__receive_internal_simple_2515_87" -> "JettonDefaultWallet__receive_internal_simple_2515_88";
"JettonDefaultWallet__receive_internal_simple_2515_88" -> "JettonDefaultWallet__receive_internal_simple_2515_89";
"JettonDefaultWallet__receive_internal_simple_2515_89" -> "JettonDefaultWallet__receive_internal_simple_2515_90";
"JettonDefaultWallet__receive_internal_simple_2515_90" -> "JettonDefaultWallet__receive_internal_simple_2515_91";
"JettonDefaultWallet__receive_internal_simple_2515_91" -> "JettonDefaultWallet__receive_internal_simple_2515_92";
"JettonDefaultWallet__receive_internal_simple_2515_92" -> "JettonDefaultWallet__receive_internal_simple_2515_93";
"JettonDefaultWallet__receive_internal_simple_2515_93" -> "JettonDefaultWallet__receive_internal_simple_2515_94";
"JettonDefaultWallet__receive_internal_simple_2515_94" -> "JettonDefaultWallet__receive_internal_simple_2515_95";
}
subgraph "cluster_JettonDefaultWallet__receive_internal_simple_2685" {
label="JettonDefaultWallet__receive_internal_simple_2685";
"JettonDefaultWallet__receive_internal_simple_2685_96" [label="let ctx: Context = context()"];
"JettonDefaultWallet__receive_internal_simple_2685_97" [label="if (ctx.sender != self.master)"];
"JettonDefaultWallet__receive_internal_simple_2685_98" [label="let sInit: StateInit = initOf JettonDefaultWallet(self.master, msg.from)"];
"JettonDefaultWallet__receive_internal_simple_2685_99" [label="require(contractAddress(sInit) == ctx.sender, \"Invalid sender!\")"];
"JettonDefaultWallet__receive_internal_simple_2685_100" [label="self.balance = self.balance + msg.amount"];
"JettonDefaultWallet__receive_internal_simple_2685_101" [label="require(self.balance >= 0, \"Invalid balance\")"];
"JettonDefaultWallet__receive_internal_simple_2685_102" [label="if (msg.forward_ton_amount > 0)"];
"JettonDefaultWallet__receive_internal_simple_2685_103" [label="send(SendParameters{to: self.owner, value: msg.forward_ton_amount, bounce: false, body: TokenNotification{queryId: msg.queryId, amount: msg.amount, from: msg.from, forward_payload: msg.forward_payload}.toCell()})"];
"JettonDefaultWallet__receive_internal_simple_2685_104" [label="let msgValue: Int = self.msgValue(ctx.value)"];
"JettonDefaultWallet__receive_internal_simple_2685_105" [label="let fwdFee: Int = ctx.readForwardFee()"];
"JettonDefaultWallet__receive_internal_simple_2685_106" [label="msgValue = msgValue - msg.forward_ton_amount - fwdFee"];
"JettonDefaultWallet__receive_internal_simple_2685_107" [label="if (msg.response_destination != null)"];
"JettonDefaultWallet__receive_internal_simple_2685_108" [label="send(SendParameters{to: !!msg.response_destination, value: msgValue, bounce: false, body: TokenExcesses{queryId: msg.queryId}.toCell(), mode: SendIgnoreErrors})",style=filled,fillcolor="#66A7DB"];
"JettonDefaultWallet__receive_internal_simple_2685_96" -> "JettonDefaultWallet__receive_internal_simple_2685_97";
"JettonDefaultWallet__receive_internal_simple_2685_97" -> "JettonDefaultWallet__receive_internal_simple_2685_98";
"JettonDefaultWallet__receive_internal_simple_2685_98" -> "JettonDefaultWallet__receive_internal_simple_2685_99";
"JettonDefaultWallet__receive_internal_simple_2685_99" -> "JettonDefaultWallet__receive_internal_simple_2685_100";
"JettonDefaultWallet__receive_internal_simple_2685_100" -> "JettonDefaultWallet__receive_internal_simple_2685_101";
"JettonDefaultWallet__receive_internal_simple_2685_101" -> "JettonDefaultWallet__receive_internal_simple_2685_102";
"JettonDefaultWallet__receive_internal_simple_2685_102" -> "JettonDefaultWallet__receive_internal_simple_2685_103";
"JettonDefaultWallet__receive_internal_simple_2685_103" -> "JettonDefaultWallet__receive_internal_simple_2685_104";
"JettonDefaultWallet__receive_internal_simple_2685_104" -> "JettonDefaultWallet__receive_internal_simple_2685_105";
"JettonDefaultWallet__receive_internal_simple_2685_105" -> "JettonDefaultWallet__receive_internal_simple_2685_106";
"JettonDefaultWallet__receive_internal_simple_2685_106" -> "JettonDefaultWallet__receive_internal_simple_2685_107";
"JettonDefaultWallet__receive_internal_simple_2685_107" -> "JettonDefaultWallet__receive_internal_simple_2685_108";
}
subgraph "cluster_JettonDefaultWallet__msgValue" {
label="JettonDefaultWallet__msgValue";
"JettonDefaultWallet__msgValue_109" [label="let tonBalanceBeforeMsg: Int = myBalance() - value"];
"JettonDefaultWallet__msgValue_110" [label="let storageFee: Int = self.minTonsForStorage - min(tonBalanceBeforeMsg, self.minTonsForStorage)"];
"JettonDefaultWallet__msgValue_111" [label="value -= storageFee + self.gasConsumption"];
"JettonDefaultWallet__msgValue_112" [label="return value",style=filled,fillcolor="#66A7DB"];
"JettonDefaultWallet__msgValue_109" -> "JettonDefaultWallet__msgValue_110";
"JettonDefaultWallet__msgValue_110" -> "JettonDefaultWallet__msgValue_111";
"JettonDefaultWallet__msgValue_111" -> "JettonDefaultWallet__msgValue_112";
}
subgraph "cluster_JettonDefaultWallet__receive_internal_simple_2830" {
label="JettonDefaultWallet__receive_internal_simple_2830";
"JettonDefaultWallet__receive_internal_simple_2830_113" [label="let ctx: Context = context()"];
"JettonDefaultWallet__receive_internal_simple_2830_114" [label="require(ctx.sender == self.owner, \"Invalid sender\")"];
"JettonDefaultWallet__receive_internal_simple_2830_115" [label="self.balance = self.balance - msg.amount"];
"JettonDefaultWallet__receive_internal_simple_2830_116" [label="require(self.balance >= 0, \"Invalid balance\")"];
"JettonDefaultWallet__receive_internal_simple_2830_117" [label="let fwdFee: Int = ctx.readForwardFee()"];
"JettonDefaultWallet__receive_internal_simple_2830_118" [label="require(ctx.value > fwdFee + 2 * self.gasConsumption + self.minTonsForStorage, \"Invalid value - Burn\")"];
"JettonDefaultWallet__receive_internal_simple_2830_119" [label="send(SendParameters{to: self.master, value: 0, mode: SendRemainingValue, bounce: true, body: TokenBurnNotification{queryId: msg.queryId, amount: msg.amount, owner: self.owner, response_destination: self.owner}.toCell()})",style=filled,fillcolor="#66A7DB"];
"JettonDefaultWallet__receive_internal_simple_2830_113" -> "JettonDefaultWallet__receive_internal_simple_2830_114";
"JettonDefaultWallet__receive_internal_simple_2830_114" -> "JettonDefaultWallet__receive_internal_simple_2830_115";
"JettonDefaultWallet__receive_internal_simple_2830_115" -> "JettonDefaultWallet__receive_internal_simple_2830_116";
"JettonDefaultWallet__receive_internal_simple_2830_116" -> "JettonDefaultWallet__receive_internal_simple_2830_117";
"JettonDefaultWallet__receive_internal_simple_2830_117" -> "JettonDefaultWallet__receive_internal_simple_2830_118";
"JettonDefaultWallet__receive_internal_simple_2830_118" -> "JettonDefaultWallet__receive_internal_simple_2830_119";
}
subgraph "cluster_JettonDefaultWallet__receive_bounce_2874" {
label="JettonDefaultWallet__receive_bounce_2874";
"JettonDefaultWallet__receive_bounce_2874_120" [label="let op: Int = msg.loadUint(32)"];
"JettonDefaultWallet__receive_bounce_2874_121" [label="let queryId: Int = msg.loadUint(64)"];
"JettonDefaultWallet__receive_bounce_2874_122" [label="let jettonAmount: Int = msg.loadCoins()"];
"JettonDefaultWallet__receive_bounce_2874_123" [label="require(op == 0x178d4519 || op == 0x7bdd97de, \"Invalid bounced message\")"];
"JettonDefaultWallet__receive_bounce_2874_124" [label="self.balance = self.balance + jettonAmount",style=filled,fillcolor="#66A7DB"];
"JettonDefaultWallet__receive_bounce_2874_120" -> "JettonDefaultWallet__receive_bounce_2874_121";
"JettonDefaultWallet__receive_bounce_2874_121" -> "JettonDefaultWallet__receive_bounce_2874_122";
"JettonDefaultWallet__receive_bounce_2874_122" -> "JettonDefaultWallet__receive_bounce_2874_123";
"JettonDefaultWallet__receive_bounce_2874_123" -> "JettonDefaultWallet__receive_bounce_2874_124";
}
subgraph "cluster_JettonDefaultWallet__get_wallet_data" {
label="JettonDefaultWallet__get_wallet_data";
"JettonDefaultWallet__get_wallet_data_125" [label="return JettonWalletData{balance: self.balance, owner: self.owner, master: self.master, walletCode: initOf JettonDefaultWallet(self.master, self.owner).code}",style=filled,fillcolor="#66A7DB"];
}
}
Loading

0 comments on commit 930a429

Please sign in to comment.