Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ update-fuel-dependencies:
update-contract-ids:
bash ./test/update-contract-ids.sh

[group('automation')]
bisect-forc path command:
bash ./scripts/bisect-forc/bisect-forc.sh "{{path}}" "{{command}}"

[group('benchmark')]
benchmark:
bash ./benchmark.sh
Expand All @@ -31,6 +35,33 @@ benchmark-tests:
collect-gas-usage:
cargo r -p test --release -- --verbose --forc-test-only | ./scripts/compare-gas-usage/extract-gas-usage.sh

# This recipe should be used on snapshot tests that contains gas usage from `forc test`,
# because it will extract gas usage from all versions of the file and generate an html interactive report.
# path: path to file to extract gas usage
# open: "-o" will open the default browser showing the report
[linux]
[group('benchmark')]
collect-historic-gas-usage path open:
#! /bin/bash
mkdir -p target
rm target/a.csv
rm target/a.html
echo "test,gas,commit" > target/a.csv
for HASH in `git log --format='%H' -- {{path}}`; do
TIMESTAMP=$(git show -s --format='%as-%ct-%H' "$HASH")
git --no-pager show "$HASH:{{path}}" | bash -c "scripts/compare-gas-usage/extract-gas-usage.sh $TIMESTAMP" >> target/a.csv
done
./scripts/csv2html/csv2html.sh target/a.csv >> target/a.html
if [ -n "{{open}}" ]; then
if which xdg-open &>> /dev/null
then
xdg-open target/a.html
elif which gnome-open &>> /dev/null
then
gnome-open target/a.html
fi
fi

[group('build')]
build-prism:
cd ./scripts/prism && ./build.sh
Expand Down
16 changes: 8 additions & 8 deletions scripts/bisect-forc/bisect-forc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ echo -n "Running: "

CACHENAME="$(git show -s --format='%as-%ct-%H' HEAD)"
compile_and_cp_to_cache "$CACHENAME"
INITIAL_COMPILATION_STATUS=$(run_cargo)
INITIAL_COMPILATION_STATUS=$(run_cargo "$1" "$2")

if [ "$INITIAL_COMPILATION_STATUS" = "0" ]; then
echo -e " ${BOLD_GREEN}Ok${NC}"
Expand All @@ -69,7 +69,7 @@ for HASH in `git log --format="%H" --tags --no-walk`; do

CACHENAME="$(git show -s --format='%as-%ct-%H' HEAD)"
compile_and_cp_to_cache "$CACHENAME"
LAST_STATUS=$(run_cargo)
LAST_STATUS=$(run_cargo "$1" "$2")
if [ "$INITIAL_COMPILATION_STATUS" != "$LAST_STATUS" ]; then
echo -e "^^^^^^^^^ ${BOLD_WHITE}This version result is different!${NC}"
break
Expand All @@ -93,22 +93,22 @@ do
#git --no-pager bisect visualize --oneline

git bisect next | grep "is the first new commit" &>> /dev/null
if [ "$LAST_STATUS" = "0" ]; then
if [ "$?" = "0" ]; then
FIRST_COMMIT="$(git bisect next 2>&1 | head -n 1 | cut -f1 -d" ")"
git checkout "$FIRST_COMMIT" &>> /dev/null
break
fi

git bisect next | grep "Bisecting"
if [ "$LAST_STATUS" != "0" ]; then
if [ "$?" != "0" ]; then
break
fi

git checkout . &>> /dev/null

CACHENAME="$(git show -s --format='%as-%ct-%H' HEAD)"
compile_and_cp_to_cache "$CACHENAME"
LAST_STATUS=$(run_cargo)
LAST_STATUS=$(run_cargo "$1" "$2")
if [ "$LAST_STATUS" = "$INITIAL_COMPILATION_STATUS" ]; then
git bisect new &>> /dev/null
else
Expand All @@ -127,7 +127,7 @@ echo -n "checking the found commit has the same behaviour as the initial commit.

CACHENAME="$(git show -s --format='%as-%ct-%H' HEAD)"
compile_and_cp_to_cache "$CACHENAME"
LAST_STATUS=$(run_cargo)
LAST_STATUS=$(run_cargo "$1" "$2")

if [ "$INITIAL_COMPILATION_STATUS" != "$LAST_STATUS" ]; then
echo -e " ${BOLD_RED}Unexpected exit code${NC}"
Expand All @@ -143,7 +143,7 @@ git checkout HEAD~1 &>> /dev/null
PREVIOUS_COMMIT="$(git show -s --format='%H' HEAD)"
CACHENAME="$(git show -s --format='%as-%ct-%H' HEAD)"
compile_and_cp_to_cache "$CACHENAME"
LAST_STATUS=$(run_cargo)
LAST_STATUS=$(run_cargo "$1" "$2")

if [ "$INITIAL_COMPILATION_STATUS" = "$LAST_STATUS" ]; then
echo -e " ${BOLD_RED}Unexpected exit code${NC}"
Expand Down
8 changes: 7 additions & 1 deletion scripts/compare-gas-usage/extract-gas-usage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# This script extracts full test names and test gas usage from a `forc test` output.
# Usage: `forc test | test_gas_usage.sh`.
# if $1 is not empty it will be appended as a new column to the csv

current_suite=""
results=()
Expand All @@ -19,7 +20,12 @@ while IFS= read -r line; do
# printf 'Test: %s\n' "$test_name"
gas="${BASH_REMATCH[2]}"
# printf 'Gas: %s\n' "$gas"
results+=("${current_suite}::${test_name},${gas}")

if [ "$1" = "" ]; then
results+=("${current_suite}::${test_name},${gas}")
else
results+=("${current_suite}::${test_name},${gas},$1")
fi
fi
done

Expand Down
60 changes: 60 additions & 0 deletions scripts/csv2html/csv2html.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash
echo '<!DOCTYPE html>
<html>
<head>
<title>Pivot Demo</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/pivot.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/pivot.min.js"></script>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/d3_renderers.min.js"></script>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/c3_renderers.min.js"></script>

<script src="https://cdn.plot.ly/plotly-basic-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pivottable/2.23.0/plotly_renderers.min.js"></script>

<style>
body {font-family: Verdana;}
.node {
border: solid 1px white;
font: 10px sans-serif;
line-height: 12px;
overflow: hidden;
position: absolute;
text-indent: 2px;
}
</style>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(function(){
var renderers = $.extend(
$.pivotUtilities.renderers,
$.pivotUtilities.c3_renderers,
$.pivotUtilities.d3_renderers,
$.pivotUtilities.plotly_renderers
);
$("#output").pivotUI($("table"), {
renderers,
rendererName: "Line Chart",
});
});
</script>
<div id="output" style="margin: 30px;"></div>
<br />
<table>
<thead>'
head -n 1 "$1" | sed -e 's/^/<tr><th>/' -e 's/,/<\/th><th>/g' -e 's/$/<\/th><\/tr>/'
echo ' </thead>
<tbody>'
tail -n +2 "$1" | sed -e 's/^/<tr><td>/' -e 's/,/<\/td><td>/g' -e 's/$/<\/td><\/tr>/'
echo " </tbody>
</table>
<body>
</html>"
2 changes: 1 addition & 1 deletion sway-core/src/decl_engine/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ impl SubstTypes for DeclId<TyConstantDecl> {
let decl_engine = ctx.engines.de();
let mut decl = (*decl_engine.get(self)).clone();
if decl.subst(ctx).has_changes() {
decl_engine.replace(*self, decl);
*self = *decl_engine.insert(decl, None).id();
HasChanges::Yes
} else {
HasChanges::No
Expand Down
7 changes: 6 additions & 1 deletion sway-core/src/type_system/ast_elements/type_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,12 @@ impl DebugWithEngines for GenericArgument {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
match self {
GenericArgument::Type(a) => {
write!(f, "{:?}", engines.help_out(&*engines.te().get(a.type_id)))
write!(
f,
"{:?} -> {:?}",
engines.help_out(&*engines.te().get(a.initial_type_id)),
engines.help_out(&*engines.te().get(a.type_id))
)
}
GenericArgument::Const(_) => {
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
Expand Down
19 changes: 19 additions & 0 deletions sway-lib-std/src/codec.sw
Original file line number Diff line number Diff line change
Expand Up @@ -2789,6 +2789,15 @@ impl<const N: u64> AbiDecode for str[N] {
}
}

#[cfg(experimental_const_generics = false)]
impl AbiDecode for str[0] {
fn abi_decode(ref mut _buffer: BufferReader) -> str[0] {
asm(s: 0) {
s: str[0]
}
}
}

// BEGIN STRARRAY_DECODE
#[cfg(experimental_const_generics = false)]
impl AbiDecode for str[1] {
Expand Down Expand Up @@ -3390,6 +3399,16 @@ where
}
}

#[cfg(experimental_const_generics = false)]
impl<T> AbiDecode for [T; 0]
where
T: AbiDecode,
{
fn abi_decode(ref mut _buffer: BufferReader) -> [T; 0] {
[]
}
}

// BEGIN ARRAY_DECODE
#[cfg(experimental_const_generics = false)]
impl<T> AbiDecode for [T; 1]
Expand Down
144 changes: 144 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Snapshot tests

There are two ways to run snapshot tests:

```
> cargo r -p test --release
> cargo r -p test --release -- -k snapshot
```

When the snapshot flag is enabled (the default) the test harness will search for `snapshot.toml` files. For every `toml` file found a new snapshot test will run. If the `toml` file is empty, it will be interpreted as simply being:

```toml
# this is how the test harness understand when it sees an empty snapshot.toml
cmds = [
\"forc build --path {root}\"
]
```

When the test harness runs a snapshot test, it will iterate the `cmds` array of each file, run each command, and append everything into the snapshot.

So the snapshot of the above file would be something like

```
> forc test --path test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/const_of_contract_call
exit status: 0
output:
Building test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/const_of_contract_call
Compiling library std (test/src/e2e_vm_tests/reduced_std_libs/sway-lib-std-core)
Compiling contract const_of_contract_call (test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/const_of_contract_call)
Finished release [optimized + fuel] target(s) [1.88 KB] in ???
```

To make snapshot "environment free", the test harness changes `forc` output a little bit.

1 - First it does not show complete file paths. All paths are relative to the swat repo root.
2 - Test harness also remove all printing of times.
3 - It also removes all ANSI codes for coloring and others.

## Commands

To make snapshot tests more versatile there are a lot of options of what one can use inside `cmds`:

1 - `forc`; Any native forc command is available;
2 - Forc plugins; Currently only `forc doc` is available;
3 - `echo`; One can use echo to write a message. Usage is:

```toml
cmds = [
"echo Explain something here.",
"forc build --path {root}",
]
```

4 - `sub`; Sub will iterate all lines of the previous command and filter in only those that contain its argument.

```toml
cmds = [
"forc build --path {root} --asm final | sub ecal"
]
```

The example above will only show asm lines that contains the `ecal` instruction.

5 - `regex`; Regex is very similar to `sub`, but allows a regex to be written.

```toml
cmds = [
"forc build --path {root} --ir initial | regex ' (v0 = call call|v0 = const|v1 = const|revert)'"
]
```

6 - `filter-fn`. This command only shows IR, ASM for a specific function. It needs that previous command return a complete IR of a program.

```toml
cmds = [
"forc build --path {root} --ir final --asm final | filter-fn {name} transmute_by_reference_7",
]
```

In the example above, the snapshot will only contain IR and asm from the function "transmute_by_reference_7"

Some commands manipulate files. These commands have an "undo" list that will restore the file original content when they a finished.
So it is guaranteed that if the test harness finishes gracefully, `main.sw` will have its original value.

For security reasons, these commands can ONLY manipulate files under its project folder.

1 - `replace`. Replace a simple string for another.

```toml
cmds = [
"replace src/main.sw \"fn cost_of_in\" \"fn isolated_cost_of_in\"",
]
```

## Variables

1 - `root`. Is the folder of the project being compiled.
2 - `name`. Is the name of the specific project being compiled.

## Blocks

Blocks are blocks of code that live inside two comments of the form below:

```rust
/* START BOOL */
#[test]
fn cost_of_in_bool() {
let _ = abi(MyContract, CONTRACT_ID).in_bool(false);
}
/* END BOOL */
```

These blocks can be manipulade from inside the snapshot.toml and allowing multiples tests to use the same project.
To manipulate these blocks one can:

1 - Use the `repeat-for-each-block`.

```toml
cmds = [
{ repeat = "for-each-block", cmds = [
"forc test --path {root} --release --experimental const_generics"
] }
]
```

In the example above, the test harness will collect all "blocks" in the project being compiled, and will run the `cmds` inside the inner table for each block, removing all others. So for example:

```rust
/* START BOOL */
#[test]
fn cost_of_in_bool() {
let _ = abi(MyContract, CONTRACT_ID).in_bool(false);
}
/* END BOOL */

/* START U8 */
#[test]
fn cost_of_in_u8() {
let _ = abi(MyContract, CONTRACT_ID).in_u8(0);
}
/* END U8 */
```

In the example above, the `repeat = "for-each-block"` means that its `cmds` list will be run twice. First removing the block `U8`; and after, it will restore the original file contents and remove "BOOL".
Loading
Loading