From 18e4eb9d7e19fed97b093697e12a6820fa14aaca Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 26 Nov 2024 15:19:51 +0100 Subject: [PATCH] feat(gnovm): test execution refactor + speedup (#3119) This PR tackles a large amount of improvements in our current internal testing systems for the gnovm, as well as those for `gno test`. The primary target is the execution of filetests; however many improvements have been implemented to remove dead or duplicate code, and bring over some of the improvements that have been implemented in tests to filetests, when they come at little added "cost". The biggest headline concerns the execution of filetests. I wrote the specific improvements undertaken in a [blog post on "diary of a gnome"](https://gno.howl.moe/faster-tests/), but here's a side-by-side comparison of the execution in this PR (left) and the execution on master (right). ![filetests](https://github.com/user-attachments/assets/049680f2-baeb-4f24-8f0f-60ae5fa4bce5) - Fixes #1084 - Fixes #2826 (by addressing root cause of slowness) - Fixes #588, only running `_long` filetests on master and generally speeding up test execution. ## Impact - Test context (tests and filetests) - Tests and filetests now share the same `test.Store` when running. Coupled with `test.LoadImports`, it allows us to "eagerly load" imports ahead of the test execution, and save it in the store. This is the primary performance improvement of this PR, as all pure packages can be run and preprocessed only once, whereas before it was once per package, and once per filetest. (More info in the blog post.) - One of the consequences of this is that package initialization happens outside of the test; so a filetest can no longer check the output of a `println` used in package initialization. - The default user no longer has 200 gnot by default. There are two mechanisms that make this unnecessary: `// SEND:`, and `std.TestIssueCoin`. Some test balances had to be updated. - Filetests - Running filetests in `gno test -v` now also prints their output. - Realm tests are no longer executed in `main.gno`, but in a filename following the name of the filetest; this changed some `// Realm:` directives. - The sytem to read directives and update them in the filetests has been re-written, and should now be more resilient and with fewer "exceptions". This means that leading and trailing whitespace in output now is correctly considered as output, leading to the addition of many empty `//` in the tests. - `// Error:` directives are now treated the same as everything else; and are updated if the `-update-golden-tests` flag is passed. - Removed the `imports` metric from the runtime metrics, as it's now no longer straightforward to calculate (given that imports are loaded "eagerly"). - Removed support for different "modes" of importing stdlibs; further removing support for gonative (#1361). The remaining gonative libraries are `os`, `fmt`, `encoding/json`, `internal/os_test` and `math/big`. This removes the `-with-native-fallback` flag from `gno test`. - Consequently, filetests ending with `_native.gno` have largely been removed, and those ending with `_stdlibs.go` have had their suffix removed. - Some files testing `gonative` types and functions which were only used in a small subset of these tests, have been removed. - Tests - `gno test`, for testing packages, created a `main_test.gno` file that is then called directly from the machine on each test. This creates two identifiers, `tests` and `runtest`, which could come into conflict with those defined by the tests themselves. We now call `testing.RunTest` directly, without an intermediary. - Exports in the normal tests (ie. defined in `pkg`) are now visible in the tests of `pkg_test`. This is most useful for some standard library tests, where there often is an `export_test.go` with the sole scope of exporting some internal functions and methods for testing in the "real" testing file. - `gno lint`, and other occasions where we use `issueFromError` (like when parsing errors in `gno test`), will now also print the column of the error if given. ## Summary of internal changes - pkg/gnolang - `TestFiles` is the new function running the filetests. - `eval_test.go` has been removed, moving some of its improvements over to `TestFiles`, and reducing the scope of the corresponding tests in `debugger.go`, to what it's actually supposed to test for. - As a consequence of removing all of type mappings in `imports.go`, I removed `SetStrictGo2GnoMapping` in favour of always being "strict", and not allowing defining native types of defined types any more. - The tests in `gonative_test` where primarily related to this, so I removed them. Similarly for `preprocess_test`. - `TestFunc` / `TestMemPackage` have been removed as redundant, including some of their features in `cmd/go/test.go` (like supporting exporting symbols in `_test.gno` files) - The `Store` no longer has `ClearCache` and `SetStrictGo2GnoMapping`; `ClearCache` now has a better substitute in `BeginTransaction`. - the `testing` stdlib no longer caches `matchPat` and `matchString` as pure packages should not be able to modify their values during execution, and as a result of other changes this was failing. - The tests/ directory has been removed / moved to `gnovm/pkg/test`. This directory should eventually contain the internal code for `gno test` as well; but for now I wanted to clean `tests` to ensure it is a directory just for integration tests, rather than code and testing systems. - `TestMachine` and `TestStore` have been renamed to Machine and Store, to avoid redundancy with the `test` package name. - Removed plenty instructions in `gnovm/Makefile` as now most tests are just in `pkg/gnolang`. - I removed `MsgContext.Msg` as unused. It can be re-added later if necessary. - In the CI, tests are now run with `-short`, at least until we figure out how to make the VM efficient enough to run these tests. Aside from some filetests, this now excludes some stdlibs: `bytes`, `strconv`, `regexp/syntax`. I accept other proposals that could make us have fast tests on PR's, while still testing (mostly) everything. --- [![Open Source Saturday](https://img.shields.io/badge/%E2%9D%A4%EF%B8%8F-open%20source%20saturday-F64060.svg)](https://lu.ma/open-source-saturday-torino) --------- Co-authored-by: Marc Vertes --- .github/workflows/examples.yml | 6 +- .github/workflows/gnovm.yml | 2 + .../gno.land/p/demo/avl/pager/z_filetest.gno | 1 + examples/gno.land/p/demo/avl/z_0_filetest.gno | 8 +- examples/gno.land/p/demo/avl/z_1_filetest.gno | 8 +- .../p/demo/tamagotchi/z0_filetest.gno | 1 + .../gno.land/r/demo/banktest/z_0_filetest.gno | 4 +- .../gno.land/r/demo/banktest/z_2_filetest.gno | 4 +- .../gno.land/r/demo/boards/z_0_filetest.gno | 2 + .../r/demo/boards/z_10_c_filetest.gno | 1 + .../r/demo/boards/z_11_d_filetest.gno | 1 + .../gno.land/r/demo/boards/z_11_filetest.gno | 1 + .../gno.land/r/demo/boards/z_12_filetest.gno | 2 + .../gno.land/r/demo/boards/z_1_filetest.gno | 1 + .../gno.land/r/demo/boards/z_2_filetest.gno | 1 + .../gno.land/r/demo/boards/z_3_filetest.gno | 1 + .../gno.land/r/demo/boards/z_4_filetest.gno | 1 + .../gno.land/r/demo/boards/z_5_c_filetest.gno | 1 + .../gno.land/r/demo/boards/z_5_filetest.gno | 1 + .../gno.land/r/demo/boards/z_6_filetest.gno | 1 + .../gno.land/r/demo/boards/z_7_filetest.gno | 2 + .../gno.land/r/demo/boards/z_8_filetest.gno | 1 + .../gno.land/r/demo/boards/z_9_filetest.gno | 1 + .../gno.land/r/demo/disperse/z_0_filetest.gno | 4 +- .../gno.land/r/demo/disperse/z_1_filetest.gno | 4 +- .../gno.land/r/demo/groups/z_0_c_filetest.gno | 1 + .../gno.land/r/demo/groups/z_1_a_filetest.gno | 2 + .../gno.land/r/demo/groups/z_2_a_filetest.gno | 2 + .../gno.land/r/demo/groups/z_2_e_filetest.gno | 2 + .../releases_example/releases0_filetest.gno | 1 + .../r/demo/tamagotchi/z0_filetest.gno | 1 + .../gno.land/r/demo/users/z_5_filetest.gno | 2 +- .../gno.land/r/demo/wugnot/z0_filetest.gno | 6 +- .../gno.land/r/gnoland/faucet/faucet_test.gno | 6 +- .../gno.land/r/gnoland/faucet/z0_filetest.gno | 2 + .../gno.land/r/gnoland/faucet/z1_filetest.gno | 2 + .../gno.land/r/gnoland/faucet/z2_filetest.gno | 2 + .../gno.land/r/gnoland/faucet/z3_filetest.gno | 2 + .../gno.land/r/gov/dao/v2/prop1_filetest.gno | 1 + .../gno.land/r/gov/dao/v2/prop4_filetest.gno | 2 + examples/gno.land/r/moul/home/z1_filetest.gno | 2 + examples/gno.land/r/moul/home/z2_filetest.gno | 2 + gno.land/pkg/sdk/vm/keeper.go | 5 - gnovm/Makefile | 20 +- gnovm/cmd/gno/lint.go | 16 +- gnovm/cmd/gno/lint_test.go | 8 +- gnovm/cmd/gno/run.go | 10 +- gnovm/cmd/gno/run_test.go | 2 +- gnovm/cmd/gno/test.go | 497 ++---------- .../gno/testdata/gno_lint/bad_import.txtar | 2 +- .../gno/testdata/gno_lint/file_error.txtar | 2 +- .../gno/testdata/gno_lint/not_declared.txtar | 2 +- .../gno/testdata/gno_test/error_correct.txtar | 1 - .../testdata/gno_test/error_incorrect.txtar | 5 +- .../gno/testdata/gno_test/error_sync.txtar | 7 +- .../testdata/gno_test/failing_filetest.txtar | 3 +- .../testdata/gno_test/filetest_events.txtar | 2 +- .../gno_test/flag_print-runtime-metrics.txtar | 3 +- .../testdata/gno_test/output_correct.txtar | 3 +- .../testdata/gno_test/output_incorrect.txtar | 7 +- .../gno/testdata/gno_test/output_sync.txtar | 6 +- .../gno_test/pkg_underscore_test.txtar | 3 +- .../gno/testdata/gno_test/realm_correct.txtar | 23 +- .../testdata/gno_test/realm_incorrect.txtar | 12 +- .../gno/testdata/gno_test/realm_sync.txtar | 28 +- .../gno_test/test_with-native-fallback.txtar | 32 - .../gno/testdata/gno_test/unknow_lib.txtar | 32 - .../testdata/gno_test/unknown_package.txtar | 24 + .../testdata/gno_test/valid_filetest.txtar | 2 +- .../gobuild_flag_build_error.txtar | 5 +- gnovm/cmd/gno/util.go | 14 - gnovm/pkg/gnolang/debugger_test.go | 33 +- gnovm/pkg/gnolang/eval_test.go | 132 ---- gnovm/pkg/gnolang/files_test.go | 141 ++++ gnovm/pkg/gnolang/gonative.go | 84 +-- gnovm/pkg/gnolang/gonative_test.go | 149 ---- gnovm/pkg/gnolang/machine.go | 157 +--- gnovm/pkg/gnolang/nodes.go | 33 - gnovm/pkg/gnolang/preprocess.go | 27 +- gnovm/pkg/gnolang/preprocess_test.go | 62 -- gnovm/pkg/gnolang/store.go | 25 +- gnovm/pkg/gnolang/store_test.go | 2 - gnovm/pkg/repl/repl.go | 6 +- gnovm/pkg/test/filetest.go | 407 ++++++++++ gnovm/pkg/test/imports.go | 265 +++++++ gnovm/pkg/test/test.go | 483 ++++++++++++ gnovm/{cmd/gno => pkg/test}/util_match.go | 2 +- gnovm/stdlibs/io/example_test.gno | 37 +- gnovm/stdlibs/io/multi_test.gno | 12 +- gnovm/stdlibs/std/context.go | 1 - gnovm/stdlibs/strconv/example_test.gno | 3 +- gnovm/stdlibs/testing/match.gno | 37 +- gnovm/stdlibs/testing/testing.gno | 2 +- gnovm/tests/README.md | 36 +- gnovm/tests/file.go | 713 ------------------ gnovm/tests/file_test.go | 144 ---- .../{access0_stdlibs.gno => access0.gno} | 0 .../{access1_stdlibs.gno => access1.gno} | 2 +- .../{access2_stdlibs.gno => access2.gno} | 0 .../{access3_stdlibs.gno => access3.gno} | 0 .../{access4_stdlibs.gno => access4.gno} | 2 +- .../{access5_stdlibs.gno => access5.gno} | 0 .../{access6_stdlibs.gno => access6.gno} | 2 +- .../{access7_stdlibs.gno => access7.gno} | 2 +- .../files/{addr0b_stdlibs.gno => addr0b.gno} | 0 gnovm/tests/files/addr0b_native.gno | 25 - gnovm/tests/files/addr2b.gno | 10 +- .../{assign0b_stdlibs.gno => assign0b.gno} | 0 gnovm/tests/files/assign0b_native.gno | 19 - ... => cross_realm_compositelit_filetest.gno} | 0 .../more/realm_compositelit_filetest.gno | 4 +- gnovm/tests/files/bin1.gno | 8 +- gnovm/tests/files/bin5.gno | 15 - gnovm/tests/files/binstruct_ptr_map0.gno | 7 +- gnovm/tests/files/binstruct_ptr_slice0.gno | 17 - gnovm/tests/files/binstruct_slice0.gno | 7 +- gnovm/tests/files/composite11.gno | 7 +- gnovm/tests/files/const14.gno | 8 +- gnovm/tests/files/const22.gno | 2 +- gnovm/tests/files/context.gno | 19 - gnovm/tests/files/context2.gno | 22 - gnovm/tests/files/defer4.gno | 23 - gnovm/tests/files/extern/p1/s1.gno | 5 - .../timtadh/data_structures/types/string.gno | 18 +- .../files/{float5_stdlibs.gno => float5.gno} | 0 gnovm/tests/files/fun6.gno | 21 - gnovm/tests/files/fun6b.gno | 20 - gnovm/tests/files/fun7.gno | 18 - gnovm/tests/files/heap_alloc_forloop9_1.gno | 2 +- gnovm/tests/files/heap_item_value.gno | 4 +- gnovm/tests/files/heap_item_value_init.gno | 8 +- gnovm/tests/files/import3.gno | 5 +- gnovm/tests/files/import5.gno | 2 - gnovm/tests/files/interp.gi | 13 - gnovm/tests/files/interp2.gi | 16 - .../tests/files/{io0_stdlibs.gno => io0.gno} | 0 gnovm/tests/files/io0_native.gno | 18 - gnovm/tests/files/io2.gno | 5 +- ...{issue_558b_stdlibs.gno => issue_558b.gno} | 4 +- gnovm/tests/files/issue_782.gno | 2 +- gnovm/tests/files/l3_long.gno | 163 ---- gnovm/tests/files/l4_long.gno | 7 - gnovm/tests/files/l5_long.gno | 164 ---- gnovm/tests/files/{l2_long.gno => loop0.gno} | 0 gnovm/tests/files/loop1.gno | 51 ++ gnovm/tests/files/map27.gno | 3 +- .../files/{map29_stdlibs.gno => map29.gno} | 0 gnovm/tests/files/map29_native.gno | 26 - .../files/{math0_stdlibs.gno => math0.gno} | 0 gnovm/tests/files/math3.gno | 25 +- .../files/{math_native.gno => math5.gno} | 0 gnovm/tests/files/method16b.gno | 2 +- gnovm/tests/files/method18.gno | 29 - gnovm/tests/files/method20.gno | 7 +- gnovm/tests/files/method24.gno | 33 - gnovm/tests/files/method25.gno | 33 - gnovm/tests/files/op0.gno | 2 +- gnovm/tests/files/print0.gno | 1 + gnovm/tests/files/sample.plugin | 19 - gnovm/tests/files/secure.gi | 33 - .../files/{std0_stdlibs.gno => std0.gno} | 0 .../files/{std10_stdlibs.gno => std10.gno} | 0 .../files/{std11_stdlibs.gno => std11.gno} | 0 .../files/{std2_stdlibs.gno => std2.gno} | 0 .../files/{std3_stdlibs.gno => std3.gno} | 0 .../files/{std4_stdlibs.gno => std4.gno} | 0 .../files/{std5_stdlibs.gno => std5.gno} | 2 +- .../files/{std6_stdlibs.gno => std6.gno} | 0 .../files/{std7_stdlibs.gno => std7.gno} | 0 .../files/{std8_stdlibs.gno => std8.gno} | 4 +- .../files/{std9_stdlibs.gno => std9.gno} | 0 .../{stdbanker_stdlibs.gno => stdbanker.gno} | 0 .../{stdlibs_stdlibs.gno => stdlibs.gno} | 0 .../{struct13_stdlibs.gno => struct13.gno} | 0 gnovm/tests/files/struct13_native.gno | 19 - gnovm/tests/files/switch21.gno | 2 +- .../files/{time0_stdlibs.gno => time0.gno} | 0 gnovm/tests/files/time0_native.gno | 13 - .../files/{time1_stdlibs.gno => time1.gno} | 0 .../files/{time11_stdlibs.gno => time11.gno} | 0 gnovm/tests/files/time11_native.gno | 15 - .../files/{time12_stdlibs.gno => time12.gno} | 0 gnovm/tests/files/time12_native.gno | 15 - .../files/{time13_stdlibs.gno => time13.gno} | 0 gnovm/tests/files/time13_native.gno | 18 - .../files/{time14_stdlibs.gno => time14.gno} | 0 gnovm/tests/files/time14_native.gno | 20 - gnovm/tests/files/time16_native.gno | 14 - gnovm/tests/files/time17_native.gno | 20 - gnovm/tests/files/time1_native.gno | 15 - .../files/{time2_stdlibs.gno => time2.gno} | 0 gnovm/tests/files/time2_native.gno | 15 - .../files/{time3_stdlibs.gno => time3.gno} | 0 gnovm/tests/files/time3_native.gno | 15 - .../files/{time4_stdlibs.gno => time4.gno} | 0 gnovm/tests/files/time4_native.gno | 15 - .../files/{time6_stdlibs.gno => time6.gno} | 0 gnovm/tests/files/time6_native.gno | 16 - .../files/{time7_stdlibs.gno => time7.gno} | 0 gnovm/tests/files/time7_native.gno | 13 - .../files/{time9_stdlibs.gno => time9.gno} | 0 gnovm/tests/files/time9_native.gno | 13 - gnovm/tests/files/type11.gno | 11 +- .../files/{type2_stdlibs.gno => type2.gno} | 0 gnovm/tests/files/type2_native.gno | 24 - ...typeassert7_native.gno => typeassert7.gno} | 0 ...peassert7a_native.gno => typeassert7a.gno} | 2 +- ...ssign_f0_stdlibs.gno => add_assign_f0.gno} | 2 +- ...ssign_f1_stdlibs.gno => add_assign_f1.gno} | 2 +- ...ssign_f2_stdlibs.gno => add_assign_f2.gno} | 2 +- .../types/{add_f0_stdlibs.gno => add_f0.gno} | 2 +- .../types/{add_f1_stdlibs.gno => add_f1.gno} | 2 +- .../types/{and_f0_stdlibs.gno => and_f0.gno} | 2 +- .../types/{and_f1_stdlibs.gno => and_f1.gno} | 2 +- ...mp_iface_0_stdlibs.gno => cmp_iface_0.gno} | 0 ...mp_iface_3_stdlibs.gno => cmp_iface_3.gno} | 0 .../{eql_0f8_stdlibs.gno => cmp_iface_5.gno} | 2 +- .../types/{eql_0b4_native.gno => eql_0b4.gno} | 2 +- gnovm/tests/files/types/eql_0b4_stdlibs.gno | 13 - .../types/{eql_0f0_native.gno => eql_0f0.gno} | 2 +- gnovm/tests/files/types/eql_0f0_stdlibs.gno | 28 - .../{eql_0f1_stdlibs.gno => eql_0f1.gno} | 2 +- .../{eql_0f27_stdlibs.gno => eql_0f27.gno} | 2 +- .../{eql_0f2b_native.gno => eql_0f2b.gno} | 2 +- gnovm/tests/files/types/eql_0f2b_stdlibs.gno | 28 - .../{eql_0f2c_native.gno => eql_0f2c.gno} | 2 +- gnovm/tests/files/types/eql_0f2c_stdlibs.gno | 28 - .../{eql_0f40_stdlibs.gno => eql_0f40.gno} | 0 .../{eql_0f41_stdlibs.gno => eql_0f41.gno} | 2 +- .../{cmp_iface_5_stdlibs.gno => eql_0f8.gno} | 2 +- .../files/types/explicit_conversion_0.gno | 2 +- .../files/types/explicit_conversion_1.gno | 2 +- .../files/types/explicit_conversion_2.gno | 2 +- .../types/{or_f0_stdlibs.gno => or_f0.gno} | 2 +- .../types/{or_f1_stdlibs.gno => or_f1.gno} | 2 +- gnovm/tests/files/types/shift_b0.gno | 2 +- gnovm/tests/files/types/shift_b1.gno | 2 +- gnovm/tests/files/types/shift_b10.gno | 2 +- gnovm/tests/files/types/shift_b11.gno | 2 +- gnovm/tests/files/types/shift_b2.gno | 2 +- gnovm/tests/files/types/shift_b3.gno | 2 +- gnovm/tests/files/types/shift_b4.gno | 2 +- gnovm/tests/files/types/shift_b5.gno | 2 +- gnovm/tests/files/types/shift_b6.gno | 2 +- gnovm/tests/files/types/shift_b6a.gno | 2 +- gnovm/tests/files/types/shift_b7.gno | 2 +- gnovm/tests/files/types/shift_b8.gno | 2 +- gnovm/tests/files/types/shift_b9.gno | 2 +- gnovm/tests/files/types/shift_c3.gno | 2 +- gnovm/tests/files/types/shift_c4.gno | 2 +- gnovm/tests/files/types/shift_c6.gno | 2 +- gnovm/tests/files/types/shift_c7.gno | 2 +- gnovm/tests/files/types/shift_c8.gno | 2 +- gnovm/tests/files/types/shift_c9.gno | 2 +- gnovm/tests/files/types/shift_d12.gno | 2 +- gnovm/tests/files/types/shift_d13.gno | 2 +- gnovm/tests/files/types/shift_d29.gno | 2 +- gnovm/tests/files/types/shift_d30.gno | 2 +- gnovm/tests/files/types/shift_d32.gno | 2 +- gnovm/tests/files/types/shift_d32a.gno | 2 +- gnovm/tests/files/types/shift_d33.gno | 2 +- gnovm/tests/files/types/shift_d34.gno | 2 +- gnovm/tests/files/types/shift_d35.gno | 2 +- gnovm/tests/files/types/shift_d39.gno | 2 +- gnovm/tests/files/types/shift_d50.gno | 2 +- gnovm/tests/files/types/shift_d53.gno | 2 +- gnovm/tests/files/types/shift_d54.gno | 2 +- gnovm/tests/files/types/shift_d55.gno | 2 +- gnovm/tests/files/types/shift_d56.gno | 2 +- gnovm/tests/files/types/shift_f5.gno | 2 +- gnovm/tests/files/types/time_native.gno | 13 - gnovm/tests/files/zrealm0.gno | 4 +- gnovm/tests/files/zrealm1.gno | 4 +- gnovm/tests/files/zrealm12_stdlibs.gno | 29 - gnovm/tests/files/zrealm2.gno | 8 +- gnovm/tests/files/zrealm3.gno | 8 +- gnovm/tests/files/zrealm4.gno | 8 +- gnovm/tests/files/zrealm5.gno | 8 +- gnovm/tests/files/zrealm6.gno | 8 +- gnovm/tests/files/zrealm7.gno | 8 +- gnovm/tests/files/zrealm_avl0.gno | 8 +- gnovm/tests/files/zrealm_avl1.gno | 8 +- ...alm_const_stdlibs.gno => zrealm_const.gno} | 0 ...lm0_stdlibs.gno => zrealm_crossrealm0.gno} | 0 ...lm1_stdlibs.gno => zrealm_crossrealm1.gno} | 0 ...10_stdlibs.gno => zrealm_crossrealm10.gno} | 0 ...11_stdlibs.gno => zrealm_crossrealm11.gno} | 0 ...12_stdlibs.gno => zrealm_crossrealm12.gno} | 0 ...13_stdlibs.gno => zrealm_crossrealm13.gno} | 0 ...a_stdlibs.gno => zrealm_crossrealm13a.gno} | 0 ...lm2_stdlibs.gno => zrealm_crossrealm2.gno} | 0 ...lm3_stdlibs.gno => zrealm_crossrealm3.gno} | 0 ...lm4_stdlibs.gno => zrealm_crossrealm4.gno} | 0 ...lm5_stdlibs.gno => zrealm_crossrealm5.gno} | 0 ...lm6_stdlibs.gno => zrealm_crossrealm6.gno} | 0 ...lm7_stdlibs.gno => zrealm_crossrealm7.gno} | 0 ...lm8_stdlibs.gno => zrealm_crossrealm8.gno} | 0 ...lm9_stdlibs.gno => zrealm_crossrealm9.gno} | 0 ...initctx_stdlibs.gno => zrealm_initctx.gno} | 0 ...tbind0_stdlibs.gno => zrealm_natbind0.gno} | 8 +- gnovm/tests/files/zrealm_panic.gno | 7 +- ...realm_std0_stdlibs.gno => zrealm_std0.gno} | 0 ...realm_std1_stdlibs.gno => zrealm_std1.gno} | 0 ...realm_std2_stdlibs.gno => zrealm_std2.gno} | 0 ...realm_std3_stdlibs.gno => zrealm_std3.gno} | 0 ...realm_std4_stdlibs.gno => zrealm_std4.gno} | 0 ...realm_std5_stdlibs.gno => zrealm_std5.gno} | 0 ...realm_std6_stdlibs.gno => zrealm_std6.gno} | 0 ...m_tests0_stdlibs.gno => zrealm_tests0.gno} | 3 + ...ils0_stdlibs.gno => zrealm_testutils0.gno} | 0 .../{zregexp_stdlibs.gno => zregexp.gno} | 0 gnovm/tests/imports.go | 492 ------------ gnovm/tests/machine_test.go | 65 -- gnovm/tests/package_test.go | 90 --- gnovm/tests/selector_test.go | 174 ----- gnovm/tests/stdlibs/generated.go | 12 - gnovm/tests/stdlibs/std/std.gno | 1 - gnovm/tests/stdlibs/std/std.go | 85 ++- .../TestMemPackage/fail/file_test.gno | 7 - .../TestMemPackage/success/file_test.gno | 5 - 320 files changed, 1928 insertions(+), 4452 deletions(-) delete mode 100644 gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar delete mode 100644 gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar create mode 100644 gnovm/cmd/gno/testdata/gno_test/unknown_package.txtar delete mode 100644 gnovm/pkg/gnolang/eval_test.go create mode 100644 gnovm/pkg/gnolang/files_test.go delete mode 100644 gnovm/pkg/gnolang/gonative_test.go delete mode 100644 gnovm/pkg/gnolang/preprocess_test.go create mode 100644 gnovm/pkg/test/filetest.go create mode 100644 gnovm/pkg/test/imports.go create mode 100644 gnovm/pkg/test/test.go rename gnovm/{cmd/gno => pkg/test}/util_match.go (99%) delete mode 100644 gnovm/tests/file.go delete mode 100644 gnovm/tests/file_test.go rename gnovm/tests/files/{access0_stdlibs.gno => access0.gno} (100%) rename gnovm/tests/files/{access1_stdlibs.gno => access1.gno} (52%) rename gnovm/tests/files/{access2_stdlibs.gno => access2.gno} (100%) rename gnovm/tests/files/{access3_stdlibs.gno => access3.gno} (100%) rename gnovm/tests/files/{access4_stdlibs.gno => access4.gno} (56%) rename gnovm/tests/files/{access5_stdlibs.gno => access5.gno} (100%) rename gnovm/tests/files/{access6_stdlibs.gno => access6.gno} (61%) rename gnovm/tests/files/{access7_stdlibs.gno => access7.gno} (67%) rename gnovm/tests/files/{addr0b_stdlibs.gno => addr0b.gno} (100%) delete mode 100644 gnovm/tests/files/addr0b_native.gno rename gnovm/tests/files/{assign0b_stdlibs.gno => assign0b.gno} (100%) delete mode 100644 gnovm/tests/files/assign0b_native.gno rename gnovm/tests/files/assign_unnamed_type/more/{cross_realm_compositelit_filetest_stdlibs.gno => cross_realm_compositelit_filetest.gno} (100%) delete mode 100644 gnovm/tests/files/bin5.gno delete mode 100644 gnovm/tests/files/binstruct_ptr_slice0.gno delete mode 100644 gnovm/tests/files/context.gno delete mode 100644 gnovm/tests/files/context2.gno delete mode 100644 gnovm/tests/files/defer4.gno delete mode 100644 gnovm/tests/files/extern/p1/s1.gno rename gnovm/tests/files/{float5_stdlibs.gno => float5.gno} (100%) delete mode 100644 gnovm/tests/files/fun6.gno delete mode 100644 gnovm/tests/files/fun6b.gno delete mode 100644 gnovm/tests/files/fun7.gno delete mode 100644 gnovm/tests/files/interp.gi delete mode 100644 gnovm/tests/files/interp2.gi rename gnovm/tests/files/{io0_stdlibs.gno => io0.gno} (100%) delete mode 100644 gnovm/tests/files/io0_native.gno rename gnovm/tests/files/{issue_558b_stdlibs.gno => issue_558b.gno} (97%) delete mode 100644 gnovm/tests/files/l3_long.gno delete mode 100644 gnovm/tests/files/l4_long.gno delete mode 100644 gnovm/tests/files/l5_long.gno rename gnovm/tests/files/{l2_long.gno => loop0.gno} (100%) create mode 100644 gnovm/tests/files/loop1.gno rename gnovm/tests/files/{map29_stdlibs.gno => map29.gno} (100%) delete mode 100644 gnovm/tests/files/map29_native.gno rename gnovm/tests/files/{math0_stdlibs.gno => math0.gno} (100%) rename gnovm/tests/files/{math_native.gno => math5.gno} (100%) delete mode 100644 gnovm/tests/files/method18.gno delete mode 100644 gnovm/tests/files/method24.gno delete mode 100644 gnovm/tests/files/method25.gno delete mode 100644 gnovm/tests/files/sample.plugin delete mode 100644 gnovm/tests/files/secure.gi rename gnovm/tests/files/{std0_stdlibs.gno => std0.gno} (100%) rename gnovm/tests/files/{std10_stdlibs.gno => std10.gno} (100%) rename gnovm/tests/files/{std11_stdlibs.gno => std11.gno} (100%) rename gnovm/tests/files/{std2_stdlibs.gno => std2.gno} (100%) rename gnovm/tests/files/{std3_stdlibs.gno => std3.gno} (100%) rename gnovm/tests/files/{std4_stdlibs.gno => std4.gno} (100%) rename gnovm/tests/files/{std5_stdlibs.gno => std5.gno} (90%) rename gnovm/tests/files/{std6_stdlibs.gno => std6.gno} (100%) rename gnovm/tests/files/{std7_stdlibs.gno => std7.gno} (100%) rename gnovm/tests/files/{std8_stdlibs.gno => std8.gno} (89%) rename gnovm/tests/files/{std9_stdlibs.gno => std9.gno} (100%) rename gnovm/tests/files/{stdbanker_stdlibs.gno => stdbanker.gno} (100%) rename gnovm/tests/files/{stdlibs_stdlibs.gno => stdlibs.gno} (100%) rename gnovm/tests/files/{struct13_stdlibs.gno => struct13.gno} (100%) delete mode 100644 gnovm/tests/files/struct13_native.gno rename gnovm/tests/files/{time0_stdlibs.gno => time0.gno} (100%) delete mode 100644 gnovm/tests/files/time0_native.gno rename gnovm/tests/files/{time1_stdlibs.gno => time1.gno} (100%) rename gnovm/tests/files/{time11_stdlibs.gno => time11.gno} (100%) delete mode 100644 gnovm/tests/files/time11_native.gno rename gnovm/tests/files/{time12_stdlibs.gno => time12.gno} (100%) delete mode 100644 gnovm/tests/files/time12_native.gno rename gnovm/tests/files/{time13_stdlibs.gno => time13.gno} (100%) delete mode 100644 gnovm/tests/files/time13_native.gno rename gnovm/tests/files/{time14_stdlibs.gno => time14.gno} (100%) delete mode 100644 gnovm/tests/files/time14_native.gno delete mode 100644 gnovm/tests/files/time16_native.gno delete mode 100644 gnovm/tests/files/time17_native.gno delete mode 100644 gnovm/tests/files/time1_native.gno rename gnovm/tests/files/{time2_stdlibs.gno => time2.gno} (100%) delete mode 100644 gnovm/tests/files/time2_native.gno rename gnovm/tests/files/{time3_stdlibs.gno => time3.gno} (100%) delete mode 100644 gnovm/tests/files/time3_native.gno rename gnovm/tests/files/{time4_stdlibs.gno => time4.gno} (100%) delete mode 100644 gnovm/tests/files/time4_native.gno rename gnovm/tests/files/{time6_stdlibs.gno => time6.gno} (100%) delete mode 100644 gnovm/tests/files/time6_native.gno rename gnovm/tests/files/{time7_stdlibs.gno => time7.gno} (100%) delete mode 100644 gnovm/tests/files/time7_native.gno rename gnovm/tests/files/{time9_stdlibs.gno => time9.gno} (100%) delete mode 100644 gnovm/tests/files/time9_native.gno rename gnovm/tests/files/{type2_stdlibs.gno => type2.gno} (100%) delete mode 100644 gnovm/tests/files/type2_native.gno rename gnovm/tests/files/{typeassert7_native.gno => typeassert7.gno} (100%) rename gnovm/tests/files/{typeassert7a_native.gno => typeassert7a.gno} (87%) rename gnovm/tests/files/types/{add_assign_f0_stdlibs.gno => add_assign_f0.gno} (71%) rename gnovm/tests/files/types/{add_assign_f1_stdlibs.gno => add_assign_f1.gno} (81%) rename gnovm/tests/files/types/{add_assign_f2_stdlibs.gno => add_assign_f2.gno} (75%) rename gnovm/tests/files/types/{add_f0_stdlibs.gno => add_f0.gno} (74%) rename gnovm/tests/files/types/{add_f1_stdlibs.gno => add_f1.gno} (75%) rename gnovm/tests/files/types/{and_f0_stdlibs.gno => and_f0.gno} (74%) rename gnovm/tests/files/types/{and_f1_stdlibs.gno => and_f1.gno} (75%) rename gnovm/tests/files/types/{cmp_iface_0_stdlibs.gno => cmp_iface_0.gno} (100%) rename gnovm/tests/files/types/{cmp_iface_3_stdlibs.gno => cmp_iface_3.gno} (100%) rename gnovm/tests/files/types/{eql_0f8_stdlibs.gno => cmp_iface_5.gno} (75%) rename gnovm/tests/files/types/{eql_0b4_native.gno => eql_0b4.gno} (50%) delete mode 100644 gnovm/tests/files/types/eql_0b4_stdlibs.gno rename gnovm/tests/files/types/{eql_0f0_native.gno => eql_0f0.gno} (75%) delete mode 100644 gnovm/tests/files/types/eql_0f0_stdlibs.gno rename gnovm/tests/files/types/{eql_0f1_stdlibs.gno => eql_0f1.gno} (76%) rename gnovm/tests/files/types/{eql_0f27_stdlibs.gno => eql_0f27.gno} (75%) rename gnovm/tests/files/types/{eql_0f2b_native.gno => eql_0f2b.gno} (80%) delete mode 100644 gnovm/tests/files/types/eql_0f2b_stdlibs.gno rename gnovm/tests/files/types/{eql_0f2c_native.gno => eql_0f2c.gno} (80%) delete mode 100644 gnovm/tests/files/types/eql_0f2c_stdlibs.gno rename gnovm/tests/files/types/{eql_0f40_stdlibs.gno => eql_0f40.gno} (100%) rename gnovm/tests/files/types/{eql_0f41_stdlibs.gno => eql_0f41.gno} (77%) rename gnovm/tests/files/types/{cmp_iface_5_stdlibs.gno => eql_0f8.gno} (75%) rename gnovm/tests/files/types/{or_f0_stdlibs.gno => or_f0.gno} (75%) rename gnovm/tests/files/types/{or_f1_stdlibs.gno => or_f1.gno} (75%) delete mode 100644 gnovm/tests/files/types/time_native.gno delete mode 100644 gnovm/tests/files/zrealm12_stdlibs.gno rename gnovm/tests/files/{zrealm_const_stdlibs.gno => zrealm_const.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm0_stdlibs.gno => zrealm_crossrealm0.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm1_stdlibs.gno => zrealm_crossrealm1.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm10_stdlibs.gno => zrealm_crossrealm10.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm11_stdlibs.gno => zrealm_crossrealm11.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm12_stdlibs.gno => zrealm_crossrealm12.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm13_stdlibs.gno => zrealm_crossrealm13.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm13a_stdlibs.gno => zrealm_crossrealm13a.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm2_stdlibs.gno => zrealm_crossrealm2.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm3_stdlibs.gno => zrealm_crossrealm3.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm4_stdlibs.gno => zrealm_crossrealm4.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm5_stdlibs.gno => zrealm_crossrealm5.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm6_stdlibs.gno => zrealm_crossrealm6.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm7_stdlibs.gno => zrealm_crossrealm7.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm8_stdlibs.gno => zrealm_crossrealm8.gno} (100%) rename gnovm/tests/files/{zrealm_crossrealm9_stdlibs.gno => zrealm_crossrealm9.gno} (100%) rename gnovm/tests/files/{zrealm_initctx_stdlibs.gno => zrealm_initctx.gno} (100%) rename gnovm/tests/files/{zrealm_natbind0_stdlibs.gno => zrealm_natbind0.gno} (95%) rename gnovm/tests/files/{zrealm_std0_stdlibs.gno => zrealm_std0.gno} (100%) rename gnovm/tests/files/{zrealm_std1_stdlibs.gno => zrealm_std1.gno} (100%) rename gnovm/tests/files/{zrealm_std2_stdlibs.gno => zrealm_std2.gno} (100%) rename gnovm/tests/files/{zrealm_std3_stdlibs.gno => zrealm_std3.gno} (100%) rename gnovm/tests/files/{zrealm_std4_stdlibs.gno => zrealm_std4.gno} (100%) rename gnovm/tests/files/{zrealm_std5_stdlibs.gno => zrealm_std5.gno} (100%) rename gnovm/tests/files/{zrealm_std6_stdlibs.gno => zrealm_std6.gno} (100%) rename gnovm/tests/files/{zrealm_tests0_stdlibs.gno => zrealm_tests0.gno} (99%) rename gnovm/tests/files/{zrealm_testutils0_stdlibs.gno => zrealm_testutils0.gno} (100%) rename gnovm/tests/files/{zregexp_stdlibs.gno => zregexp.gno} (100%) delete mode 100644 gnovm/tests/imports.go delete mode 100644 gnovm/tests/machine_test.go delete mode 100644 gnovm/tests/package_test.go delete mode 100644 gnovm/tests/selector_test.go delete mode 100644 gnovm/tests/testdata/TestMemPackage/fail/file_test.gno delete mode 100644 gnovm/tests/testdata/TestMemPackage/success/file_test.gno diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 7c4bb35526f..41d579c4567 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -3,7 +3,7 @@ name: examples on: pull_request: push: - branches: [ "master" ] + branches: ["master"] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} @@ -70,7 +70,7 @@ jobs: strategy: fail-fast: false matrix: - goversion: [ "1.22.x" ] + goversion: ["1.22.x"] runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -86,7 +86,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [ "1.22.x" ] + go-version: ["1.22.x"] # unittests: TODO: matrix with contracts runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/.github/workflows/gnovm.yml b/.github/workflows/gnovm.yml index 7e7586b23d9..8311d113047 100644 --- a/.github/workflows/gnovm.yml +++ b/.github/workflows/gnovm.yml @@ -13,6 +13,8 @@ jobs: uses: ./.github/workflows/main_template.yml with: modulepath: "gnovm" + # in pull requests, append -short so that the CI runs quickly. + tests-extra-args: ${{ github.event_name == 'pull_request' && '-short' || '' }} secrets: codecov-token: ${{ secrets.CODECOV_TOKEN }} fmt: diff --git a/examples/gno.land/p/demo/avl/pager/z_filetest.gno b/examples/gno.land/p/demo/avl/pager/z_filetest.gno index 91c20115469..17029f57861 100644 --- a/examples/gno.land/p/demo/avl/pager/z_filetest.gno +++ b/examples/gno.land/p/demo/avl/pager/z_filetest.gno @@ -99,3 +99,4 @@ func main() { // // ## Page 7 of 6 // [1](?page=1) | … | [5](?page=5) | [6](?page=6) | _7_ +// diff --git a/examples/gno.land/p/demo/avl/z_0_filetest.gno b/examples/gno.land/p/demo/avl/z_0_filetest.gno index aff79ffabc6..2dce5e7f1ac 100644 --- a/examples/gno.land/p/demo/avl/z_0_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_0_filetest.gno @@ -267,7 +267,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "z_0.gno", // "IsMethod": false, // "Name": "init.1", // "NativeName": "", @@ -278,7 +278,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "z_0.gno", // "Line": "10", // "PkgPath": "gno.land/r/test" // } @@ -303,7 +303,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "z_0.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", @@ -314,7 +314,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "z_0.gno", // "Line": "15", // "PkgPath": "gno.land/r/test" // } diff --git a/examples/gno.land/p/demo/avl/z_1_filetest.gno b/examples/gno.land/p/demo/avl/z_1_filetest.gno index 3b6d40d5ecd..97ca5ed2135 100644 --- a/examples/gno.land/p/demo/avl/z_1_filetest.gno +++ b/examples/gno.land/p/demo/avl/z_1_filetest.gno @@ -340,7 +340,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "z_1.gno", // "IsMethod": false, // "Name": "init.1", // "NativeName": "", @@ -351,7 +351,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "z_1.gno", // "Line": "10", // "PkgPath": "gno.land/r/test" // } @@ -376,7 +376,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "z_1.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", @@ -387,7 +387,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "z_1.gno", // "Line": "15", // "PkgPath": "gno.land/r/test" // } diff --git a/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno b/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno index 4b2c04b6d5c..17d6c466ed5 100644 --- a/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno +++ b/examples/gno.land/p/demo/tamagotchi/z0_filetest.gno @@ -44,6 +44,7 @@ func main() { } // Output: +// // -- INITIAL // // # Gnome 😃 diff --git a/examples/gno.land/r/demo/banktest/z_0_filetest.gno b/examples/gno.land/r/demo/banktest/z_0_filetest.gno index 61289dfe071..5a8c8d70a48 100644 --- a/examples/gno.land/r/demo/banktest/z_0_filetest.gno +++ b/examples/gno.land/r/demo/banktest/z_0_filetest.gno @@ -42,9 +42,9 @@ func main() { } // Output: -// main before: 300000000ugnot +// main before: 100000000ugnot // Deposit(): returned! -// main after: 250000000ugnot +// main after: 50000000ugnot // ## recent activity // // * g1tnpdmvrmtgql8fmxgsq9rwtst5hsxahk3f05dk 100000000ugnot sent, 50000000ugnot returned, at 2009-02-13 11:31pm UTC diff --git a/examples/gno.land/r/demo/banktest/z_2_filetest.gno b/examples/gno.land/r/demo/banktest/z_2_filetest.gno index 2dc9c84e767..e839f60354a 100644 --- a/examples/gno.land/r/demo/banktest/z_2_filetest.gno +++ b/examples/gno.land/r/demo/banktest/z_2_filetest.gno @@ -39,9 +39,9 @@ func main() { } // Output: -// main before: 200000000ugnot +// main before: // Deposit(): returned! -// main after: 255000000ugnot +// main after: 55000000ugnot // ## recent activity // // * g1tnpdmvrmtgql8fmxgsq9rwtst5hsxahk3f05dk 100000000ugnot sent, 55000000ugnot returned, at 2009-02-13 11:31pm UTC diff --git a/examples/gno.land/r/demo/boards/z_0_filetest.gno b/examples/gno.land/r/demo/boards/z_0_filetest.gno index 4fc224da9b2..a649895cb01 100644 --- a/examples/gno.land/r/demo/boards/z_0_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_0_filetest.gno @@ -37,3 +37,5 @@ func main() { // // Body of the second post. (body) // \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm UTC](/r/demo/boards:test_board/2) \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=2)] (1 replies) (0 reposts) +// +// diff --git a/examples/gno.land/r/demo/boards/z_10_c_filetest.gno b/examples/gno.land/r/demo/boards/z_10_c_filetest.gno index f746877b5c7..7dd460500d6 100644 --- a/examples/gno.land/r/demo/boards/z_10_c_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_10_c_filetest.gno @@ -46,3 +46,4 @@ func main() { // // Body of the first post. (body) // \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards$help&func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=1&postid=1)] +// diff --git a/examples/gno.land/r/demo/boards/z_11_d_filetest.gno b/examples/gno.land/r/demo/boards/z_11_d_filetest.gno index de2b6aa463b..f64b4c84bba 100644 --- a/examples/gno.land/r/demo/boards/z_11_d_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_11_d_filetest.gno @@ -50,3 +50,4 @@ func main() { // > Edited: First reply of the First post // > // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=1&postid=2)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=1&postid=2)] +// diff --git a/examples/gno.land/r/demo/boards/z_11_filetest.gno b/examples/gno.land/r/demo/boards/z_11_filetest.gno index 49ee0ee0273..3f56293b3bd 100644 --- a/examples/gno.land/r/demo/boards/z_11_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_11_filetest.gno @@ -40,3 +40,4 @@ func main() { // // Edited: Body of the first post. (body) // \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=1&postid=1)] \[[repost](/r/demo/boards$help&func=CreateRepost&bid=1&postid=1)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=1&postid=1)] +// diff --git a/examples/gno.land/r/demo/boards/z_12_filetest.gno b/examples/gno.land/r/demo/boards/z_12_filetest.gno index 02953352dd2..ac4adf6ee7b 100644 --- a/examples/gno.land/r/demo/boards/z_12_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_12_filetest.gno @@ -38,3 +38,5 @@ func main() { // // Body of the first post. (body) // \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm UTC](/r/demo/boards:test_board1/1) \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=1&postid=1)] (0 replies) (1 reposts) +// +// diff --git a/examples/gno.land/r/demo/boards/z_1_filetest.gno b/examples/gno.land/r/demo/boards/z_1_filetest.gno index ba0a277e2f1..4d46c81b83d 100644 --- a/examples/gno.land/r/demo/boards/z_1_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_1_filetest.gno @@ -26,3 +26,4 @@ func main() { // // * [/r/demo/boards:test_board_1](/r/demo/boards:test_board_1) // * [/r/demo/boards:test_board_2](/r/demo/boards:test_board_2) +// diff --git a/examples/gno.land/r/demo/boards/z_2_filetest.gno b/examples/gno.land/r/demo/boards/z_2_filetest.gno index 53c0a1965da..31b39644b24 100644 --- a/examples/gno.land/r/demo/boards/z_2_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_2_filetest.gno @@ -36,3 +36,4 @@ func main() { // // > Reply of the second post // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=3)] +// diff --git a/examples/gno.land/r/demo/boards/z_3_filetest.gno b/examples/gno.land/r/demo/boards/z_3_filetest.gno index 89e5a3f12ff..0b2a2df2f91 100644 --- a/examples/gno.land/r/demo/boards/z_3_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_3_filetest.gno @@ -38,3 +38,4 @@ func main() { // // > Reply of the second post // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/3) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=2&postid=3)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=3)] +// diff --git a/examples/gno.land/r/demo/boards/z_4_filetest.gno b/examples/gno.land/r/demo/boards/z_4_filetest.gno index fa0b9e20be5..c6cf6397b3a 100644 --- a/examples/gno.land/r/demo/boards/z_4_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_4_filetest.gno @@ -44,6 +44,7 @@ func main() { // // > Second reply of the second post // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=2&postid=4)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=4)] +// // Realm: // switchrealm["gno.land/r/demo/users"] diff --git a/examples/gno.land/r/demo/boards/z_5_c_filetest.gno b/examples/gno.land/r/demo/boards/z_5_c_filetest.gno index b20d8cdfed8..723e6a10204 100644 --- a/examples/gno.land/r/demo/boards/z_5_c_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_5_c_filetest.gno @@ -37,3 +37,4 @@ func main() { // // > Reply of the first post // > \- [g1w3jhxapjta047h6lta047h6lta047h6laqcyu4](/r/demo/users:g1w3jhxapjta047h6lta047h6lta047h6laqcyu4), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/1/2) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=1&postid=2)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=1&postid=2)] +// diff --git a/examples/gno.land/r/demo/boards/z_5_filetest.gno b/examples/gno.land/r/demo/boards/z_5_filetest.gno index c0614bb9da3..712af483891 100644 --- a/examples/gno.land/r/demo/boards/z_5_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_5_filetest.gno @@ -41,3 +41,4 @@ func main() { // > Second reply of the second post // > // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=2&postid=4)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=4)] +// diff --git a/examples/gno.land/r/demo/boards/z_6_filetest.gno b/examples/gno.land/r/demo/boards/z_6_filetest.gno index 6ddd8b9cf3f..ec40cf5f8e9 100644 --- a/examples/gno.land/r/demo/boards/z_6_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_6_filetest.gno @@ -47,3 +47,4 @@ func main() { // > Second reply of the second post // > // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/4) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=2&postid=4)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=4)] +// diff --git a/examples/gno.land/r/demo/boards/z_7_filetest.gno b/examples/gno.land/r/demo/boards/z_7_filetest.gno index 534095b99cf..353b84f6d87 100644 --- a/examples/gno.land/r/demo/boards/z_7_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_7_filetest.gno @@ -29,3 +29,5 @@ func main() { // // Body of the first post. (body) // \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm UTC](/r/demo/boards:test_board/1) \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=1&postid=1)] (0 replies) (0 reposts) +// +// diff --git a/examples/gno.land/r/demo/boards/z_8_filetest.gno b/examples/gno.land/r/demo/boards/z_8_filetest.gno index f5477026805..4896dfcfccf 100644 --- a/examples/gno.land/r/demo/boards/z_8_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_8_filetest.gno @@ -42,3 +42,4 @@ func main() { // > First reply of the first reply // > // > \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:test_board/2/5) \[[reply](/r/demo/boards$help&func=CreateReply&bid=1&threadid=2&postid=5)] \[[x](/r/demo/boards$help&func=DeletePost&bid=1&threadid=2&postid=5)] +// diff --git a/examples/gno.land/r/demo/boards/z_9_filetest.gno b/examples/gno.land/r/demo/boards/z_9_filetest.gno index 4be9d2bdfa6..ca37e306bda 100644 --- a/examples/gno.land/r/demo/boards/z_9_filetest.gno +++ b/examples/gno.land/r/demo/boards/z_9_filetest.gno @@ -35,3 +35,4 @@ func main() { // // Body of the first post. (body) // \- [@gnouser](/r/demo/users:gnouser), [2009-02-13 11:31pm (UTC)](/r/demo/boards:second_board/1/1) \[[reply](/r/demo/boards$help&func=CreateReply&bid=2&threadid=1&postid=1)] \[[x](/r/demo/boards$help&func=DeletePost&bid=2&threadid=1&postid=1)] +// diff --git a/examples/gno.land/r/demo/disperse/z_0_filetest.gno b/examples/gno.land/r/demo/disperse/z_0_filetest.gno index e54b34ae3bf..ca1e9ea0ce8 100644 --- a/examples/gno.land/r/demo/disperse/z_0_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_0_filetest.gno @@ -30,5 +30,5 @@ func main() { } // Output: -// main before: 200000200ugnot -// main after: 200000000ugnot +// main before: 200ugnot +// main after: diff --git a/examples/gno.land/r/demo/disperse/z_1_filetest.gno b/examples/gno.land/r/demo/disperse/z_1_filetest.gno index 62018fe965e..4c27c50749f 100644 --- a/examples/gno.land/r/demo/disperse/z_1_filetest.gno +++ b/examples/gno.land/r/demo/disperse/z_1_filetest.gno @@ -30,5 +30,5 @@ func main() { } // Output: -// main before: 200000300ugnot -// main after: 200000100ugnot +// main before: 300ugnot +// main after: 100ugnot diff --git a/examples/gno.land/r/demo/groups/z_0_c_filetest.gno b/examples/gno.land/r/demo/groups/z_0_c_filetest.gno index cf5902928db..60600e38b78 100644 --- a/examples/gno.land/r/demo/groups/z_0_c_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_0_c_filetest.gno @@ -22,3 +22,4 @@ func main() { // List of all Groups: // // * [test_group](/r/demo/groups:test_group) +// diff --git a/examples/gno.land/r/demo/groups/z_1_a_filetest.gno b/examples/gno.land/r/demo/groups/z_1_a_filetest.gno index 18799e31a67..71da1b966ec 100644 --- a/examples/gno.land/r/demo/groups/z_1_a_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_1_a_filetest.gno @@ -76,3 +76,5 @@ func main() { // Group Members: // // [0000000000, g1vahx7atnv4erxh6lta047h6lta047h6ll85gpy, 32, i am from UAE, 2009-02-13 23:31:30 +0000 UTC m=+1234567890.000000001], +// +// diff --git a/examples/gno.land/r/demo/groups/z_2_a_filetest.gno b/examples/gno.land/r/demo/groups/z_2_a_filetest.gno index 7c97b01ccf5..0c482e1b52f 100644 --- a/examples/gno.land/r/demo/groups/z_2_a_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_2_a_filetest.gno @@ -76,3 +76,5 @@ func main() { // Group Last MemberID: 0000000001 // // Group Members: +// +// diff --git a/examples/gno.land/r/demo/groups/z_2_e_filetest.gno b/examples/gno.land/r/demo/groups/z_2_e_filetest.gno index cbfff97c7a7..ff38acf45a4 100644 --- a/examples/gno.land/r/demo/groups/z_2_e_filetest.gno +++ b/examples/gno.land/r/demo/groups/z_2_e_filetest.gno @@ -21,3 +21,5 @@ func main() { // Output: // 1 // List of all Groups: +// +// diff --git a/examples/gno.land/r/demo/releases_example/releases0_filetest.gno b/examples/gno.land/r/demo/releases_example/releases0_filetest.gno index 193f9bdbc90..ca599a54892 100644 --- a/examples/gno.land/r/demo/releases_example/releases0_filetest.gno +++ b/examples/gno.land/r/demo/releases_example/releases0_filetest.gno @@ -49,3 +49,4 @@ func main() { // // * various improvements // * new shiny logo +// diff --git a/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno b/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno index 1ea56b4a3f9..4072c0b30d7 100644 --- a/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno +++ b/examples/gno.land/r/demo/tamagotchi/z0_filetest.gno @@ -23,3 +23,4 @@ func main() { // * [Play](/r/demo/tamagotchi$help&func=Play) // * [Heal](/r/demo/tamagotchi$help&func=Heal) // * [Reset](/r/demo/tamagotchi$help&func=Reset) +// diff --git a/examples/gno.land/r/demo/users/z_5_filetest.gno b/examples/gno.land/r/demo/users/z_5_filetest.gno index dcb957f2155..6465cc9c378 100644 --- a/examples/gno.land/r/demo/users/z_5_filetest.gno +++ b/examples/gno.land/r/demo/users/z_5_filetest.gno @@ -38,7 +38,7 @@ func main() { } // Output: -// * [archives](/r/demo/users:archives) +// * [archives](/r/demo/users:archives) // * [demo](/r/demo/users:demo) // * [gno](/r/demo/users:gno) // * [gnoland](/r/demo/users:gnoland) diff --git a/examples/gno.land/r/demo/wugnot/z0_filetest.gno b/examples/gno.land/r/demo/wugnot/z0_filetest.gno index bef65c03b68..264bc8f19aa 100644 --- a/examples/gno.land/r/demo/wugnot/z0_filetest.gno +++ b/examples/gno.land/r/demo/wugnot/z0_filetest.gno @@ -55,17 +55,17 @@ func printBalances() { // Output: // ----------- -// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=0 | ugnot=200000000 | +// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=0 | ugnot=0 | // | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 | // | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 | // ----------- // ----------- -// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=123400 | ugnot=200000000 | +// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=123400 | ugnot=0 | // | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 | // | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 | // ----------- // ----------- -// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=119158 | ugnot=200004242 | +// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=119158 | ugnot=4242 | // | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=99995759 | // | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 | // ----------- diff --git a/examples/gno.land/r/gnoland/faucet/faucet_test.gno b/examples/gno.land/r/gnoland/faucet/faucet_test.gno index 1f492adb2dc..cecbb2ebcd6 100644 --- a/examples/gno.land/r/gnoland/faucet/faucet_test.gno +++ b/examples/gno.land/r/gnoland/faucet/faucet_test.gno @@ -28,7 +28,7 @@ func TestPackage(t *testing.T) { ) // deposit 1000gnot to faucet contract std.TestIssueCoins(faucetaddr, std.Coins{{"ugnot", 1000000000}}) - assertBalance(t, faucetaddr, 1200000000) + assertBalance(t, faucetaddr, 1000000000) // by default, balance is empty, and as a user I cannot call Transfer, or Admin commands. @@ -43,7 +43,7 @@ func TestPackage(t *testing.T) { // as an admin, add the controller to contract and deposit more 2000gnot to contract std.TestSetOrigCaller(adminaddr) assertNoErr(t, faucet.AdminAddController(controlleraddr1)) - assertBalance(t, faucetaddr, 1200000000) + assertBalance(t, faucetaddr, 1000000000) // now, send some tokens as controller. std.TestSetOrigCaller(controlleraddr1) @@ -51,7 +51,7 @@ func TestPackage(t *testing.T) { assertBalance(t, test1addr, 1000000) assertNoErr(t, faucet.Transfer(test1addr, 1000000)) assertBalance(t, test1addr, 2000000) - assertBalance(t, faucetaddr, 1198000000) + assertBalance(t, faucetaddr, 998000000) // remove controller // as an admin, remove controller diff --git a/examples/gno.land/r/gnoland/faucet/z0_filetest.gno b/examples/gno.land/r/gnoland/faucet/z0_filetest.gno index bcc75897c85..7e729bdd358 100644 --- a/examples/gno.land/r/gnoland/faucet/z0_filetest.gno +++ b/examples/gno.land/r/gnoland/faucet/z0_filetest.gno @@ -33,3 +33,5 @@ func main() { // // // Per request limit: 350000000ugnot +// +// diff --git a/examples/gno.land/r/gnoland/faucet/z1_filetest.gno b/examples/gno.land/r/gnoland/faucet/z1_filetest.gno index 6afb14b024b..c6fd6298488 100644 --- a/examples/gno.land/r/gnoland/faucet/z1_filetest.gno +++ b/examples/gno.land/r/gnoland/faucet/z1_filetest.gno @@ -33,3 +33,5 @@ func main() { // // // Per request limit: 350000000ugnot +// +// diff --git a/examples/gno.land/r/gnoland/faucet/z2_filetest.gno b/examples/gno.land/r/gnoland/faucet/z2_filetest.gno index 054e5329476..d0616b3afcd 100644 --- a/examples/gno.land/r/gnoland/faucet/z2_filetest.gno +++ b/examples/gno.land/r/gnoland/faucet/z2_filetest.gno @@ -48,3 +48,5 @@ func main() { // g1vdhkuarjdakxcetjx9047h6lta047h6lsdacav g1vdhkuarjdakxcetjxf047h6lta047h6lnrev3v // // Per request limit: 350000000ugnot +// +// diff --git a/examples/gno.land/r/gnoland/faucet/z3_filetest.gno b/examples/gno.land/r/gnoland/faucet/z3_filetest.gno index 4a48ca390e2..0da06593710 100644 --- a/examples/gno.land/r/gnoland/faucet/z3_filetest.gno +++ b/examples/gno.land/r/gnoland/faucet/z3_filetest.gno @@ -60,3 +60,5 @@ func main() { // g1vdhkuarjdakxcetjx9047h6lta047h6lsdacav g1vdhkuarjdakxcetjxf047h6lta047h6lnrev3v // // Per request limit: 350000000ugnot +// +// diff --git a/examples/gno.land/r/gov/dao/v2/prop1_filetest.gno b/examples/gno.land/r/gov/dao/v2/prop1_filetest.gno index e889dde4f48..7b25eeb1db3 100644 --- a/examples/gno.land/r/gov/dao/v2/prop1_filetest.gno +++ b/examples/gno.land/r/gov/dao/v2/prop1_filetest.gno @@ -126,6 +126,7 @@ func main() { // - #123: g12345678 (10) // - #123: g000000000 (10) // - #123: g000000000 (0) +// // Events: // [ diff --git a/examples/gno.land/r/gov/dao/v2/prop4_filetest.gno b/examples/gno.land/r/gov/dao/v2/prop4_filetest.gno index c90e76727da..8eff79ffb5a 100644 --- a/examples/gno.land/r/gov/dao/v2/prop4_filetest.gno +++ b/examples/gno.land/r/gov/dao/v2/prop4_filetest.gno @@ -80,6 +80,8 @@ func main() { // Voting stats: YES 10 (100%), NO 0 (0%), ABSTAIN 0 (0%), MISSING VOTE 0 (0%) // // Threshold met: true +// +// // Events: // [ diff --git a/examples/gno.land/r/moul/home/z1_filetest.gno b/examples/gno.land/r/moul/home/z1_filetest.gno index 5203e07ada7..b26c919dd3a 100644 --- a/examples/gno.land/r/moul/home/z1_filetest.gno +++ b/examples/gno.land/r/moul/home/z1_filetest.gno @@ -17,3 +17,5 @@ func main() { // // ## Personal ToDo List // - [ ] fill this todo list... +// +// diff --git a/examples/gno.land/r/moul/home/z2_filetest.gno b/examples/gno.land/r/moul/home/z2_filetest.gno index 02d08cd591e..489dc2aeecd 100644 --- a/examples/gno.land/r/moul/home/z2_filetest.gno +++ b/examples/gno.land/r/moul/home/z2_filetest.gno @@ -33,3 +33,5 @@ func main() { // - [ ] bbb // - [ ] ddd // - [ ] eee +// +// diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 5fa2075b8f7..0dca794ee71 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -365,7 +365,6 @@ func (vm *VMKeeper) AddPackage(ctx sdk.Context, msg MsgAddPackage) (err error) { ChainID: ctx.ChainID(), Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), - Msg: msg, OrigCaller: creator.Bech32(), OrigSend: deposit, OrigSendSpent: new(std.Coins), @@ -466,7 +465,6 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { ChainID: ctx.ChainID(), Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), - Msg: msg, OrigCaller: caller.Bech32(), OrigSend: send, OrigSendSpent: new(std.Coins), @@ -565,7 +563,6 @@ func (vm *VMKeeper) Run(ctx sdk.Context, msg MsgRun) (res string, err error) { ChainID: ctx.ChainID(), Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), - Msg: msg, OrigCaller: caller.Bech32(), OrigSend: send, OrigSendSpent: new(std.Coins), @@ -729,7 +726,6 @@ func (vm *VMKeeper) QueryEval(ctx sdk.Context, pkgPath string, expr string) (res ChainID: ctx.ChainID(), Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), - // Msg: msg, // OrigCaller: caller, // OrigSend: send, // OrigSendSpent: nil, @@ -796,7 +792,6 @@ func (vm *VMKeeper) QueryEvalString(ctx sdk.Context, pkgPath string, expr string ChainID: ctx.ChainID(), Height: ctx.BlockHeight(), Timestamp: ctx.BlockTime().Unix(), - // Msg: msg, // OrigCaller: caller, // OrigSend: jsend, // OrigSendSpent: nil, diff --git a/gnovm/Makefile b/gnovm/Makefile index d27395d9cd1..31daf942554 100644 --- a/gnovm/Makefile +++ b/gnovm/Makefile @@ -64,7 +64,7 @@ imports: ######################################## # Test suite .PHONY: test -test: _test.cmd _test.pkg _test.gnolang +test: _test.cmd _test.pkg _test.stdlibs .PHONY: _test.cmd _test.cmd: @@ -92,20 +92,10 @@ test.cmd.coverage_view: test.cmd.coverage _test.pkg: go test ./pkg/... $(GOTEST_FLAGS) -.PHONY: _test.gnolang -_test.gnolang: _test.gnolang.native _test.gnolang.stdlibs _test.gnolang.realm _test.gnolang.pkg0 _test.gnolang.pkg1 _test.gnolang.pkg2 _test.gnolang.other -_test.gnolang.other:; go test tests/*.go -run "(TestFileStr|TestSelectors)" $(GOTEST_FLAGS) -_test.gnolang.realm:; go test tests/*.go -run "TestFiles/^zrealm" $(GOTEST_FLAGS) -_test.gnolang.pkg0:; go test tests/*.go -run "TestStdlibs/(bufio|crypto|encoding|errors|internal|io|math|sort|std|strconv|strings|testing|unicode)" $(GOTEST_FLAGS) -_test.gnolang.pkg1:; go test tests/*.go -run "TestStdlibs/regexp" $(GOTEST_FLAGS) -_test.gnolang.pkg2:; go test tests/*.go -run "TestStdlibs/bytes" $(GOTEST_FLAGS) -_test.gnolang.native:; go test tests/*.go -test.short -run "TestFilesNative/" $(GOTEST_FLAGS) -_test.gnolang.stdlibs:; go test tests/*.go -test.short -run 'TestFiles$$/' $(GOTEST_FLAGS) -_test.gnolang.native.sync:; go test tests/*.go -test.short -run "TestFilesNative/" --update-golden-tests $(GOTEST_FLAGS) -_test.gnolang.stdlibs.sync:; go test tests/*.go -test.short -run 'TestFiles$$/' --update-golden-tests $(GOTEST_FLAGS) -# NOTE: challenges are current GnoVM bugs which are supposed to fail. -# If any of these tests pass, it should be moved to a normal test. -_test.gnolang.challenges:; go test tests/*.go -test.short -run 'TestChallenges$$/' $(GOTEST_FLAGS) +.PHONY: _test.stdlibs +_test.stdlibs: + go run ./cmd/gno test -v ./stdlibs/... + ######################################## # Code gen diff --git a/gnovm/cmd/gno/lint.go b/gnovm/cmd/gno/lint.go index c6008117f13..ef35cf9af83 100644 --- a/gnovm/cmd/gno/lint.go +++ b/gnovm/cmd/gno/lint.go @@ -14,7 +14,7 @@ import ( "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/tests" + "github.com/gnolang/gno/gnovm/pkg/test" "github.com/gnolang/gno/tm2/pkg/commands" osm "github.com/gnolang/gno/tm2/pkg/os" "go.uber.org/multierr" @@ -91,10 +91,9 @@ func execLint(cfg *lintCfg, args []string, io commands.IO) error { // Handle runtime errors hasError = catchRuntimeError(pkgPath, io.Err(), func() { stdout, stdin, stderr := io.Out(), io.In(), io.Err() - testStore := tests.TestStore( - rootDir, "", + _, testStore := test.Store( + rootDir, false, stdin, stdout, stderr, - tests.ImportModeStdlibsOnly, ) targetPath := pkgPath @@ -104,7 +103,8 @@ func execLint(cfg *lintCfg, args []string, io commands.IO) error { } memPkg := gno.ReadMemPackage(targetPath, targetPath) - tm := tests.TestMachine(testStore, stdout, memPkg.Name) + tm := test.Machine(testStore, stdout, memPkg.Path) + defer tm.Release() // Check package tm.RunMemPackage(memPkg, true) @@ -161,7 +161,7 @@ func guessSourcePath(pkg, source string) string { // reParseRecover is a regex designed to parse error details from a string. // It extracts the file location, line number, and error message from a formatted error string. // XXX: Ideally, error handling should encapsulate location details within a dedicated error type. -var reParseRecover = regexp.MustCompile(`^([^:]+):(\d+)(?::\d+)?:? *(.*)$`) +var reParseRecover = regexp.MustCompile(`^([^:]+)((?::(?:\d+)){1,2}):? *(.*)$`) func catchRuntimeError(pkgPath string, stderr io.WriteCloser, action func()) (hasError bool) { defer func() { @@ -230,9 +230,9 @@ func issueFromError(pkgPath string, err error) lintIssue { parsedError = strings.TrimPrefix(parsedError, pkgPath+"/") matches := reParseRecover.FindStringSubmatch(parsedError) - if len(matches) == 4 { + if len(matches) > 0 { sourcepath := guessSourcePath(pkgPath, matches[1]) - issue.Location = fmt.Sprintf("%s:%s", sourcepath, matches[2]) + issue.Location = sourcepath + matches[2] issue.Msg = strings.TrimSpace(matches[3]) } else { issue.Location = fmt.Sprintf("%s:0", filepath.Clean(pkgPath)) diff --git a/gnovm/cmd/gno/lint_test.go b/gnovm/cmd/gno/lint_test.go index 20d21c05d05..031c252bc79 100644 --- a/gnovm/cmd/gno/lint_test.go +++ b/gnovm/cmd/gno/lint_test.go @@ -13,19 +13,19 @@ func TestLintApp(t *testing.T) { errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/undefined_variable_test/undefined_variables_test.gno"}, - stderrShouldContain: "undefined_variables_test.gno:6: name toto not declared (code=2)", + stderrShouldContain: "undefined_variables_test.gno:6:28: name toto not declared (code=2)", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/package_not_declared/main.gno"}, - stderrShouldContain: "main.gno:4: name fmt not declared (code=2).", + stderrShouldContain: "main.gno:4:2: name fmt not declared (code=2).", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/several-lint-errors/main.gno"}, - stderrShouldContain: "../../tests/integ/several-lint-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-lint-errors/main.gno:6", + stderrShouldContain: "../../tests/integ/several-lint-errors/main.gno:5:5: expected ';', found example (code=2).\n../../tests/integ/several-lint-errors/main.gno:6", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/several-files-multiple-errors/main.gno"}, - stderrShouldContain: "../../tests/integ/several-files-multiple-errors/file2.gno:3: expected 'IDENT', found '{' (code=2).\n../../tests/integ/several-files-multiple-errors/file2.gno:5: expected type, found '}' (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:6: expected '}', found 'EOF' (code=2).\n", + stderrShouldContain: "../../tests/integ/several-files-multiple-errors/file2.gno:3:5: expected 'IDENT', found '{' (code=2).\n../../tests/integ/several-files-multiple-errors/file2.gno:5:1: expected type, found '}' (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:5:5: expected ';', found example (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:6:2: expected '}', found 'EOF' (code=2).\n", errShouldBe: "exit code: 1", }, { args: []string{"lint", "../../tests/integ/run_main/"}, diff --git a/gnovm/cmd/gno/run.go b/gnovm/cmd/gno/run.go index f174c2b4cc5..9a9beac5cd1 100644 --- a/gnovm/cmd/gno/run.go +++ b/gnovm/cmd/gno/run.go @@ -12,7 +12,7 @@ import ( "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/tests" + "github.com/gnolang/gno/gnovm/pkg/test" "github.com/gnolang/gno/tm2/pkg/commands" "github.com/gnolang/gno/tm2/pkg/std" ) @@ -92,9 +92,9 @@ func execRun(cfg *runCfg, args []string, io commands.IO) error { stderr := io.Err() // init store and machine - testStore := tests.TestStore(cfg.rootDir, - "", stdin, stdout, stderr, - tests.ImportModeStdlibsPreferred) + _, testStore := test.Store( + cfg.rootDir, false, + stdin, stdout, stderr) if cfg.verbose { testStore.SetLogStoreOps(true) } @@ -115,7 +115,7 @@ func execRun(cfg *runCfg, args []string, io commands.IO) error { var send std.Coins pkgPath := string(files[0].PkgName) - ctx := tests.TestContext(pkgPath, send) + ctx := test.Context(pkgPath, send) m := gno.NewMachineWithOptions(gno.MachineOptions{ PkgPath: pkgPath, Output: stdout, diff --git a/gnovm/cmd/gno/run_test.go b/gnovm/cmd/gno/run_test.go index e5aa1bd6279..74f99f7490c 100644 --- a/gnovm/cmd/gno/run_test.go +++ b/gnovm/cmd/gno/run_test.go @@ -85,7 +85,7 @@ func TestRunApp(t *testing.T) { }, { args: []string{"run", "../../tests/integ/several-files-multiple-errors/"}, - stderrShouldContain: "../../tests/integ/several-files-multiple-errors/file2.gno:3: expected 'IDENT', found '{' (code=2).\n../../tests/integ/several-files-multiple-errors/file2.gno:5: expected type, found '}' (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:6: expected '}', found 'EOF' (code=2).", + stderrShouldContain: "../../tests/integ/several-files-multiple-errors/file2.gno:3:5: expected 'IDENT', found '{' (code=2).\n../../tests/integ/several-files-multiple-errors/file2.gno:5:1: expected type, found '}' (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:5:5: expected ';', found example (code=2).\n../../tests/integ/several-files-multiple-errors/main.gno:6:2: expected '}', found 'EOF' (code=2).\n", errShouldBe: "exit code: 1", }, // TODO: a test file diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index d54b12f6a4f..04a3808718d 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -1,33 +1,21 @@ package main import ( - "bytes" "context" - "encoding/json" "flag" "fmt" + goio "io" "log" - "math" - "os" "path/filepath" - "runtime/debug" - "sort" "strings" - "text/template" "time" - "go.uber.org/multierr" - - "github.com/gnolang/gno/gnovm" "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/pkg/gnomod" - "github.com/gnolang/gno/gnovm/tests" - teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" + "github.com/gnolang/gno/gnovm/pkg/test" "github.com/gnolang/gno/tm2/pkg/commands" - "github.com/gnolang/gno/tm2/pkg/errors" "github.com/gnolang/gno/tm2/pkg/random" - "github.com/gnolang/gno/tm2/pkg/testutils" ) type testCfg struct { @@ -38,7 +26,6 @@ type testCfg struct { updateGoldenTests bool printRuntimeMetrics bool printEvents bool - withNativeFallback bool } func newTestCmd(io commands.IO) *commands.Command { @@ -66,34 +53,38 @@ module name found in 'gno.mod', or else it is randomly generated like - "*_filetest.gno" files on the other hand are kind of unique. They exist to provide a way to interact and assert a gno contract, thanks to a set of -specific instructions that can be added using code comments. +specific directives that can be added using code comments. "*_filetest.gno" must be declared in the 'main' package and so must have a 'main' function, that will be executed to test the target contract. -List of available instructions that can be used in "*_filetest.gno" files: - - "PKGPATH:" is a single line instruction that can be used to define the +These single-line directives can set "input parameters" for the machine used +to perform the test: + - "PKGPATH:" is a single line directive that can be used to define the package used to interact with the tested package. If not specified, "main" is used. - - "MAXALLOC:" is a signle line instruction that can be used to define a limit + - "MAXALLOC:" is a single line directive that can be used to define a limit to the VM allocator. If this limit is exceeded, the VM will panic. Default to 0, no limit. - - "SEND:" is a single line instruction that can be used to send an amount of + - "SEND:" is a single line directive that can be used to send an amount of token along with the transaction. The format is for example "1000000ugnot". Default is empty. - - "Output:\n" (*) is a multiple lines instruction that can be used to assert - the output of the "*_filetest.gno" file. Any prints executed inside the - 'main' function must match the lines that follows the "Output:\n" - instruction, or else the test fails. - - "Error:\n" works similarly to "Output:\n", except that it asserts the - stderr of the program, which in that case, comes from the VM because of a - panic, rather than the 'main' function. - - "Realm:\n" (*) is a multiple lines instruction that can be used to assert - what has been recorded in the store following the execution of the 'main' - function. - -(*) The 'update-golden-tests' flag can be set to fill out the content of the -instruction with the actual content of the test instead of failing. + +These directives, instead, match the comment that follows with the result +of the GnoVM, acting as a "golden test": + - "Output:" tests the following comment with the standard output of the + filetest. + - "Error:" tests the following comment with any panic, or other kind of + error that the filetest generates (like a parsing or preprocessing error). + - "Realm:" tests the following comment against the store log, which can show + what realm information is stored. + - "Stacktrace:" can be used to verify the following lines against the + stacktrace of the error. + - "Events:" can be used to verify the emitted events against a JSON. + +To speed up execution, imports of pure packages are processed separately from +the execution of the tests. This makes testing faster, but means that the +initialization of imported pure packages cannot be checked in filetests. `, }, cfg, @@ -115,7 +106,7 @@ func (c *testCfg) RegisterFlags(fs *flag.FlagSet) { &c.updateGoldenTests, "update-golden-tests", false, - `writes actual as wanted for "Output:" and "Realm:" instructions`, + `writes actual as wanted for "golden" directives in filetests`, ) fs.StringVar( @@ -139,13 +130,6 @@ func (c *testCfg) RegisterFlags(fs *flag.FlagSet) { "max execution time", ) - fs.BoolVar( - &c.withNativeFallback, - "with-native-fallback", - false, - "use stdlibs/* if present, otherwise use supported native Go packages", - ) - fs.BoolVar( &c.printRuntimeMetrics, "print-runtime-metrics", @@ -192,6 +176,18 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { return fmt.Errorf("list sub packages: %w", err) } + // Set up options to run tests. + stdout := goio.Discard + if cfg.verbose { + stdout = io.Out() + } + opts := test.NewTestOptions(cfg.rootDir, io.In(), stdout, io.Err()) + opts.RunFlag = cfg.run + opts.Sync = cfg.updateGoldenTests + opts.Verbose = cfg.verbose + opts.Metrics = cfg.printRuntimeMetrics + opts.Events = cfg.printEvents + buildErrCount := 0 testErrCount := 0 for _, pkg := range subPkgs { @@ -199,200 +195,48 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { io.ErrPrintfln("? %s \t[no test files]", pkg.Dir) continue } - - sort.Strings(pkg.TestGnoFiles) - sort.Strings(pkg.FiletestGnoFiles) - - startedAt := time.Now() - err = gnoTestPkg(pkg.Dir, pkg.TestGnoFiles, pkg.FiletestGnoFiles, cfg, io) - duration := time.Since(startedAt) - dstr := fmtDuration(duration) - - if err != nil { - io.ErrPrintfln("%s: test pkg: %v", pkg.Dir, err) - io.ErrPrintfln("FAIL") - io.ErrPrintfln("FAIL %s \t%s", pkg.Dir, dstr) - io.ErrPrintfln("FAIL") - testErrCount++ - } else { - io.ErrPrintfln("ok %s \t%s", pkg.Dir, dstr) - } - } - if testErrCount > 0 || buildErrCount > 0 { - io.ErrPrintfln("FAIL") - return fmt.Errorf("FAIL: %d build errors, %d test errors", buildErrCount, testErrCount) - } - - return nil -} - -func gnoTestPkg( - pkgPath string, - unittestFiles, - filetestFiles []string, - cfg *testCfg, - io commands.IO, -) error { - var ( - verbose = cfg.verbose - rootDir = cfg.rootDir - runFlag = cfg.run - printRuntimeMetrics = cfg.printRuntimeMetrics - printEvents = cfg.printEvents - - stdin = io.In() - stdout = io.Out() - stderr = io.Err() - errs error - ) - - mode := tests.ImportModeStdlibsOnly - if cfg.withNativeFallback { - // XXX: display a warn? - mode = tests.ImportModeStdlibsPreferred - } - if !verbose { - // TODO: speedup by ignoring if filter is file/*? - mockOut := bytes.NewBufferString("") - stdout = commands.WriteNopCloser(mockOut) - } - - // testing with *_test.gno - if len(unittestFiles) > 0 { // Determine gnoPkgPath by reading gno.mod var gnoPkgPath string - modfile, err := gnomod.ParseAt(pkgPath) + modfile, err := gnomod.ParseAt(pkg.Dir) if err == nil { gnoPkgPath = modfile.Module.Mod.Path } else { - gnoPkgPath = pkgPathFromRootDir(pkgPath, rootDir) + gnoPkgPath = pkgPathFromRootDir(pkg.Dir, cfg.rootDir) if gnoPkgPath == "" { // unable to read pkgPath from gno.mod, generate a random realm path io.ErrPrintfln("--- WARNING: unable to read package path from gno.mod or gno root directory; try creating a gno.mod file") - gnoPkgPath = gno.RealmPathPrefix + random.RandStr(8) + gnoPkgPath = gno.RealmPathPrefix + strings.ToLower(random.RandStr(8)) } } - memPkg := gno.ReadMemPackage(pkgPath, gnoPkgPath) - // tfiles, ifiles := gno.ParseMemPackageTests(memPkg) - var tfiles, ifiles *gno.FileSet + memPkg := gno.ReadMemPackage(pkg.Dir, gnoPkgPath) - hasError := catchRuntimeError(gnoPkgPath, stderr, func() { - tfiles, ifiles = parseMemPackageTests(memPkg) + startedAt := time.Now() + hasError := catchRuntimeError(gnoPkgPath, io.Err(), func() { + err = test.Test(memPkg, pkg.Dir, opts) }) - if hasError { - return commands.ExitCodeError(1) - } - testPkgName := getPkgNameFromFileset(ifiles) - - // run test files in pkg - if len(tfiles.Files) > 0 { - testStore := tests.TestStore( - rootDir, "", - stdin, stdout, stderr, - mode, - ) - if verbose { - testStore.SetLogStoreOps(true) - } - - m := tests.TestMachine(testStore, stdout, gnoPkgPath) - if printRuntimeMetrics { - // from tm2/pkg/sdk/vm/keeper.go - // XXX: make maxAllocTx configurable. - maxAllocTx := int64(math.MaxInt64) - - m.Alloc = gno.NewAllocator(maxAllocTx) - } - m.RunMemPackage(memPkg, true) - err := runTestFiles(m, tfiles, memPkg.Name, verbose, printRuntimeMetrics, printEvents, runFlag, io) - if err != nil { - errs = multierr.Append(errs, err) - } - } - - // test xxx_test pkg - if len(ifiles.Files) > 0 { - testStore := tests.TestStore( - rootDir, "", - stdin, stdout, stderr, - mode, - ) - if verbose { - testStore.SetLogStoreOps(true) - } - - m := tests.TestMachine(testStore, stdout, testPkgName) - - memFiles := make([]*gnovm.MemFile, 0, len(ifiles.FileNames())+1) - for _, f := range memPkg.Files { - for _, ifileName := range ifiles.FileNames() { - if f.Name == "gno.mod" || f.Name == ifileName { - memFiles = append(memFiles, f) - break - } - } - } - - memPkg.Files = memFiles - memPkg.Name = testPkgName - memPkg.Path = memPkg.Path + "_test" - m.RunMemPackage(memPkg, true) + duration := time.Since(startedAt) + dstr := fmtDuration(duration) - err := runTestFiles(m, ifiles, testPkgName, verbose, printRuntimeMetrics, printEvents, runFlag, io) + if hasError || err != nil { if err != nil { - errs = multierr.Append(errs, err) + io.ErrPrintfln("%s: test pkg: %v", pkg.Dir, err) } + io.ErrPrintfln("FAIL") + io.ErrPrintfln("FAIL %s \t%s", pkg.Dir, dstr) + io.ErrPrintfln("FAIL") + testErrCount++ + } else { + io.ErrPrintfln("ok %s \t%s", pkg.Dir, dstr) } } - - // testing with *_filetest.gno - { - filter := splitRegexp(runFlag) - for _, testFile := range filetestFiles { - testFileName := filepath.Base(testFile) - testName := "file/" + testFileName - if !shouldRun(filter, testName) { - continue - } - - startedAt := time.Now() - if verbose { - io.ErrPrintfln("=== RUN %s", testName) - } - - var closer func() (string, error) - if !verbose { - closer = testutils.CaptureStdoutAndStderr() - } - - testFilePath := filepath.Join(pkgPath, testFileName) - err := tests.RunFileTest(rootDir, testFilePath, tests.WithSyncWanted(cfg.updateGoldenTests)) - duration := time.Since(startedAt) - dstr := fmtDuration(duration) - - if err != nil { - errs = multierr.Append(errs, err) - io.ErrPrintfln("--- FAIL: %s (%s)", testName, dstr) - if verbose { - stdouterr, err := closer() - if err != nil { - panic(err) - } - fmt.Fprintln(os.Stderr, stdouterr) - } - continue - } - - if verbose { - io.ErrPrintfln("--- PASS: %s (%s)", testName, dstr) - } - // XXX: add per-test metrics - } + if testErrCount > 0 || buildErrCount > 0 { + io.ErrPrintfln("FAIL") + return fmt.Errorf("FAIL: %d build errors, %d test errors", buildErrCount, testErrCount) } - return errs + return nil } // attempts to determine the full gno pkg path by analyzing the directory. @@ -423,228 +267,3 @@ func pkgPathFromRootDir(pkgPath, rootDir string) string { } return "" } - -func runTestFiles( - m *gno.Machine, - files *gno.FileSet, - pkgName string, - verbose bool, - printRuntimeMetrics bool, - printEvents bool, - runFlag string, - io commands.IO, -) (errs error) { - defer func() { - if r := recover(); r != nil { - errs = multierr.Append(fmt.Errorf("panic: %v\nstack:\n%v\ngno machine: %v", r, string(debug.Stack()), m.String()), errs) - } - }() - - testFuncs := &testFuncs{ - PackageName: pkgName, - Verbose: verbose, - RunFlag: runFlag, - } - loadTestFuncs(pkgName, testFuncs, files) - - // before/after statistics - numPackagesBefore := m.Store.NumMemPackages() - - testmain, err := formatTestmain(testFuncs) - if err != nil { - log.Fatal(err) - } - - m.RunFiles(files.Files...) - n := gno.MustParseFile("main_test.gno", testmain) - m.RunFiles(n) - - for _, test := range testFuncs.Tests { - // cleanup machine between tests - tests.CleanupMachine(m) - - testFuncStr := fmt.Sprintf("%q", test.Name) - - eval := m.Eval(gno.Call("runtest", testFuncStr)) - - if printEvents { - events := m.Context.(*teststd.TestExecContext).EventLogger.Events() - if events != nil { - res, err := json.Marshal(events) - if err != nil { - panic(err) - } - io.ErrPrintfln("EVENTS: %s", string(res)) - } - } - - ret := eval[0].GetString() - if ret == "" { - err := errors.New("failed to execute unit test: %q", test.Name) - errs = multierr.Append(errs, err) - io.ErrPrintfln("--- FAIL: %s [internal gno testing error]", test.Name) - continue - } - - // TODO: replace with amino or send native type? - var rep report - err = json.Unmarshal([]byte(ret), &rep) - if err != nil { - errs = multierr.Append(errs, err) - io.ErrPrintfln("--- FAIL: %s [internal gno testing error]", test.Name) - continue - } - - if rep.Failed { - err := errors.New("failed: %q", test.Name) - errs = multierr.Append(errs, err) - } - - if printRuntimeMetrics { - imports := m.Store.NumMemPackages() - numPackagesBefore - 1 - // XXX: store changes - // XXX: max mem consumption - allocsVal := "n/a" - if m.Alloc != nil { - maxAllocs, allocs := m.Alloc.Status() - allocsVal = fmt.Sprintf("%s(%.2f%%)", - prettySize(allocs), - float64(allocs)/float64(maxAllocs)*100, - ) - } - io.ErrPrintfln("--- runtime: cycle=%s imports=%d allocs=%s", - prettySize(m.Cycles), - imports, - allocsVal, - ) - } - } - - return errs -} - -// mirror of stdlibs/testing.Report -type report struct { - Failed bool - Skipped bool -} - -var testmainTmpl = template.Must(template.New("testmain").Parse(` -package {{ .PackageName }} - -import ( - "testing" -) - -var tests = []testing.InternalTest{ -{{range .Tests}} - {"{{.Name}}", {{.Name}}}, -{{end}} -} - -func runtest(name string) (report string) { - for _, test := range tests { - if test.Name == name { - return testing.RunTest({{printf "%q" .RunFlag}}, {{.Verbose}}, test) - } - } - panic("no such test: " + name) - return "" -} -`)) - -type testFuncs struct { - Tests []testFunc - PackageName string - Verbose bool - RunFlag string -} - -type testFunc struct { - Package string - Name string -} - -func getPkgNameFromFileset(files *gno.FileSet) string { - if len(files.Files) <= 0 { - return "" - } - return string(files.Files[0].PkgName) -} - -func formatTestmain(t *testFuncs) (string, error) { - var buf bytes.Buffer - if err := testmainTmpl.Execute(&buf, t); err != nil { - return "", err - } - return buf.String(), nil -} - -func loadTestFuncs(pkgName string, t *testFuncs, tfiles *gno.FileSet) *testFuncs { - for _, tf := range tfiles.Files { - for _, d := range tf.Decls { - if fd, ok := d.(*gno.FuncDecl); ok { - fname := string(fd.Name) - if strings.HasPrefix(fname, "Test") { - tf := testFunc{ - Package: pkgName, - Name: fname, - } - t.Tests = append(t.Tests, tf) - } - } - } - } - return t -} - -// parseMemPackageTests is copied from gno.ParseMemPackageTests -// for except to _filetest.gno -func parseMemPackageTests(memPkg *gnovm.MemPackage) (tset, itset *gno.FileSet) { - tset = &gno.FileSet{} - itset = &gno.FileSet{} - var errs error - for _, mfile := range memPkg.Files { - if !strings.HasSuffix(mfile.Name, ".gno") { - continue // skip this file. - } - if strings.HasSuffix(mfile.Name, "_filetest.gno") { - continue - } - n, err := gno.ParseFile(mfile.Name, mfile.Body) - if err != nil { - errs = multierr.Append(errs, err) - continue - } - if n == nil { - panic("should not happen") - } - if strings.HasSuffix(mfile.Name, "_test.gno") { - // add test file. - if memPkg.Name+"_test" == string(n.PkgName) { - itset.AddFiles(n) - } else { - tset.AddFiles(n) - } - } else if memPkg.Name == string(n.PkgName) { - // skip package file. - } else { - panic(fmt.Sprintf( - "expected package name [%s] or [%s_test] but got [%s] file [%s]", - memPkg.Name, memPkg.Name, n.PkgName, mfile)) - } - } - if errs != nil { - panic(errs) - } - return tset, itset -} - -func shouldRun(filter filterMatch, path string) bool { - if filter == nil { - return true - } - elem := strings.Split(path, "/") - ok, _ := filter.matches(elem, matchString) - return ok -} diff --git a/gnovm/cmd/gno/testdata/gno_lint/bad_import.txtar b/gnovm/cmd/gno/testdata/gno_lint/bad_import.txtar index fc4039d38c6..52141dff09b 100644 --- a/gnovm/cmd/gno/testdata/gno_lint/bad_import.txtar +++ b/gnovm/cmd/gno/testdata/gno_lint/bad_import.txtar @@ -16,4 +16,4 @@ func main() { -- stdout.golden -- -- stderr.golden -- -bad_file.gno:3: unknown import path python (code=2). +bad_file.gno:3:8: unknown import path python (code=2). diff --git a/gnovm/cmd/gno/testdata/gno_lint/file_error.txtar b/gnovm/cmd/gno/testdata/gno_lint/file_error.txtar index 9482eeb1f4f..5aa3a3282d5 100644 --- a/gnovm/cmd/gno/testdata/gno_lint/file_error.txtar +++ b/gnovm/cmd/gno/testdata/gno_lint/file_error.txtar @@ -17,4 +17,4 @@ func TestIHaveSomeError() { -- stdout.golden -- -- stderr.golden -- -i_have_error_test.gno:6: name undefined_variable not declared (code=2). +i_have_error_test.gno:6:7: name undefined_variable not declared (code=2). diff --git a/gnovm/cmd/gno/testdata/gno_lint/not_declared.txtar b/gnovm/cmd/gno/testdata/gno_lint/not_declared.txtar index 7bd74a34855..b63c5c447e1 100644 --- a/gnovm/cmd/gno/testdata/gno_lint/not_declared.txtar +++ b/gnovm/cmd/gno/testdata/gno_lint/not_declared.txtar @@ -17,4 +17,4 @@ func main() { -- stdout.golden -- -- stderr.golden -- -bad_file.gno:6: name hello not declared (code=2). +bad_file.gno:6:3: name hello not declared (code=2). diff --git a/gnovm/cmd/gno/testdata/gno_test/error_correct.txtar b/gnovm/cmd/gno/testdata/gno_test/error_correct.txtar index 20a399881be..f9ce4dd9028 100644 --- a/gnovm/cmd/gno/testdata/gno_test/error_correct.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/error_correct.txtar @@ -2,7 +2,6 @@ gno test -v . -stdout 'Machine\.RunMain\(\) panic: oups' stderr '=== RUN file/x_filetest.gno' stderr '--- PASS: file/x_filetest.gno \(\d\.\d\ds\)' stderr 'ok \. \d\.\d\ds' diff --git a/gnovm/cmd/gno/testdata/gno_test/error_incorrect.txtar b/gnovm/cmd/gno/testdata/gno_test/error_incorrect.txtar index 00737d8dd67..621397d8d1f 100644 --- a/gnovm/cmd/gno/testdata/gno_test/error_incorrect.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/error_incorrect.txtar @@ -2,9 +2,10 @@ ! gno test -v . -stdout 'Machine\.RunMain\(\) panic: oups' stderr '=== RUN file/x_filetest.gno' -stderr 'panic: fail on x_filetest.gno: got "oups", want: "xxx"' +stderr 'Error diff:' +stderr '-xxx' +stderr '\+oups' -- x_filetest.gno -- package main diff --git a/gnovm/cmd/gno/testdata/gno_test/error_sync.txtar b/gnovm/cmd/gno/testdata/gno_test/error_sync.txtar index e2b67cb3333..067489c41f2 100644 --- a/gnovm/cmd/gno/testdata/gno_test/error_sync.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/error_sync.txtar @@ -3,9 +3,9 @@ # by the '-update-golden-tests' flag. The Error is only updated when it is # empty. -! gno test -v . +gno test -update-golden-tests -v . -stdout 'Machine\.RunMain\(\) panic: oups' +! stdout .+ stderr '=== RUN file/x_filetest.gno' cmp x_filetest.gno x_filetest.gno.golden @@ -18,7 +18,6 @@ func main() { } // Error: - -- x_filetest.gno.golden -- package main @@ -28,5 +27,3 @@ func main() { // Error: // oups -// *** CHECK THE ERR MESSAGES ABOVE, MAKE SURE IT'S WHAT YOU EXPECTED, DELETE THIS LINE AND RUN TEST AGAIN *** - diff --git a/gnovm/cmd/gno/testdata/gno_test/failing_filetest.txtar b/gnovm/cmd/gno/testdata/gno_test/failing_filetest.txtar index 91431e4f7bb..7b57729ee91 100644 --- a/gnovm/cmd/gno/testdata/gno_test/failing_filetest.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/failing_filetest.txtar @@ -2,9 +2,8 @@ ! gno test -v . -stdout 'Machine.RunMain\(\) panic: beep boop' stderr '=== RUN file/failing_filetest.gno' -stderr 'panic: fail on failing_filetest.gno: got unexpected error: beep boop' +stderr 'unexpected panic: beep boop' -- failing.gno -- package failing diff --git a/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar b/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar index 0236872e78a..34da5fe2ff0 100644 --- a/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/filetest_events.txtar @@ -7,7 +7,7 @@ stderr 'ok \. \d\.\d\ds' gno test -print-events -v . -! stdout .+ +stdout 'test' stderr '=== RUN file/valid_filetest.gno' stderr '--- PASS: file/valid_filetest.gno \(\d\.\d\ds\)' stderr 'ok \. \d\.\d\ds' diff --git a/gnovm/cmd/gno/testdata/gno_test/flag_print-runtime-metrics.txtar b/gnovm/cmd/gno/testdata/gno_test/flag_print-runtime-metrics.txtar index e065d00d55a..99747a0a241 100644 --- a/gnovm/cmd/gno/testdata/gno_test/flag_print-runtime-metrics.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/flag_print-runtime-metrics.txtar @@ -3,7 +3,7 @@ gno test --print-runtime-metrics . ! stdout .+ -stderr '--- runtime: cycle=[\d\.kM]+ imports=\d+ allocs=[\d\.kM]+\(\d\.\d\d%\)' +stderr '--- runtime: cycle=[\d\.kM]+ allocs=[\d\.kM]+\(\d\.\d\d%\)' -- metrics.gno -- package metrics @@ -20,4 +20,3 @@ func TestTimeout(t *testing.T) { println("plop") } } - diff --git a/gnovm/cmd/gno/testdata/gno_test/output_correct.txtar b/gnovm/cmd/gno/testdata/gno_test/output_correct.txtar index e734dad7934..a8aa878e0a4 100644 --- a/gnovm/cmd/gno/testdata/gno_test/output_correct.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/output_correct.txtar @@ -2,7 +2,8 @@ gno test -v . -! stdout .+ # stdout should be empty +stdout 'hey' +stdout 'hru?' stderr '=== RUN file/x_filetest.gno' stderr '--- PASS: file/x_filetest.gno \(\d\.\d\ds\)' stderr 'ok \. \d\.\d\ds' diff --git a/gnovm/cmd/gno/testdata/gno_test/output_incorrect.txtar b/gnovm/cmd/gno/testdata/gno_test/output_incorrect.txtar index 009d09623a0..60a38933d47 100644 --- a/gnovm/cmd/gno/testdata/gno_test/output_incorrect.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/output_incorrect.txtar @@ -1,13 +1,14 @@ # Test Output instruction incorrect +# with -v, stdout should contain output (unmodified). ! gno test -v . -! stdout .+ # stdout should be empty +stdout 'hey' + stderr '=== RUN file/x_filetest.gno' -stderr 'panic: fail on x_filetest.gno: diff:' stderr '--- Expected' stderr '\+\+\+ Actual' -stderr '@@ -1,2 \+1 @@' +stderr '@@ -1,3 \+1,2 @@' stderr 'hey' stderr '-hru?' diff --git a/gnovm/cmd/gno/testdata/gno_test/output_sync.txtar b/gnovm/cmd/gno/testdata/gno_test/output_sync.txtar index 45e6e5c79be..45385a7eef9 100644 --- a/gnovm/cmd/gno/testdata/gno_test/output_sync.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/output_sync.txtar @@ -2,7 +2,9 @@ gno test -v . -update-golden-tests -! stdout .+ # stdout should be empty +stdout 'hey' +stdout '^hru\?' + stderr '=== RUN file/x_filetest.gno' stderr '--- PASS: file/x_filetest.gno \(\d\.\d\ds\)' stderr 'ok \. \d\.\d\ds' @@ -19,7 +21,6 @@ func main() { // Output: // hey - -- x_filetest.gno.golden -- package main @@ -31,4 +32,3 @@ func main() { // Output: // hey // hru? - diff --git a/gnovm/cmd/gno/testdata/gno_test/pkg_underscore_test.txtar b/gnovm/cmd/gno/testdata/gno_test/pkg_underscore_test.txtar index b38683adf81..7d204bdb98d 100644 --- a/gnovm/cmd/gno/testdata/gno_test/pkg_underscore_test.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/pkg_underscore_test.txtar @@ -66,4 +66,5 @@ func main() { println("filetest " + hello.Name) } -// Output: filetest foo +// Output: +// filetest foo diff --git a/gnovm/cmd/gno/testdata/gno_test/realm_correct.txtar b/gnovm/cmd/gno/testdata/gno_test/realm_correct.txtar index 99e6fccd42d..ced183bec67 100644 --- a/gnovm/cmd/gno/testdata/gno_test/realm_correct.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/realm_correct.txtar @@ -8,8 +8,8 @@ stderr '--- PASS: file/x_filetest.gno \(\d\.\d\ds\)' stderr 'ok \. \d\.\d\ds' -- x_filetest.gno -- -// PKGPATH: gno.land/r/x -package x +// PKGPATH: gno.land/r/xx +package xx var x int @@ -18,11 +18,11 @@ func main() { } // Realm: -// switchrealm["gno.land/r/x"] -// u[58cde29876a8d185e30c727361981efb068f4726:2]={ +// switchrealm["gno.land/r/xx"] +// u[aea84df38908f9569d0f552575606e6e6e7e22dd:2]={ // "Blank": {}, // "ObjectInfo": { -// "ID": "58cde29876a8d185e30c727361981efb068f4726:2", +// "ID": "aea84df38908f9569d0f552575606e6e6e7e22dd:2", // "IsEscaped": true, // "ModTime": "3", // "RefCount": "2" @@ -35,7 +35,7 @@ func main() { // "Column": "0", // "File": "", // "Line": "0", -// "PkgPath": "gno.land/r/x" +// "PkgPath": "gno.land/r/xx" // } // }, // "Values": [ @@ -57,22 +57,22 @@ func main() { // "Closure": { // "@type": "/gno.RefValue", // "Escaped": true, -// "ObjectID": "58cde29876a8d185e30c727361981efb068f4726:3" +// "ObjectID": "aea84df38908f9569d0f552575606e6e6e7e22dd:3" // }, -// "FileName": "main.gno", +// "FileName": "x.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", // "NativePkg": "", -// "PkgPath": "gno.land/r/x", +// "PkgPath": "gno.land/r/xx", // "Source": { // "@type": "/gno.RefNode", // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "x.gno", // "Line": "6", -// "PkgPath": "gno.land/r/x" +// "PkgPath": "gno.land/r/xx" // } // }, // "Type": { @@ -84,4 +84,3 @@ func main() { // } // ] // } - diff --git a/gnovm/cmd/gno/testdata/gno_test/realm_incorrect.txtar b/gnovm/cmd/gno/testdata/gno_test/realm_incorrect.txtar index 6dfd6d70bb9..234d0f81e77 100644 --- a/gnovm/cmd/gno/testdata/gno_test/realm_incorrect.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/realm_incorrect.txtar @@ -4,16 +4,17 @@ ! stdout .+ # stdout should be empty stderr '=== RUN file/x_filetest.gno' -stderr 'panic: fail on x_filetest.gno: diff:' +stderr 'Realm diff:' stderr '--- Expected' stderr '\+\+\+ Actual' -stderr '@@ -1 \+1,66 @@' +stderr '@@ -1,2 \+1,67 @@' stderr '-xxx' -stderr '\+switchrealm\["gno.land/r/x"\]' +stderr '\+switchrealm\["gno.land/r/xx"\]' +stderr 'x_filetest.gno failed' -- x_filetest.gno -- -// PKGPATH: gno.land/r/x -package x +// PKGPATH: gno.land/r/xx +package xx var x int @@ -23,4 +24,3 @@ func main() { // Realm: // xxxx - diff --git a/gnovm/cmd/gno/testdata/gno_test/realm_sync.txtar b/gnovm/cmd/gno/testdata/gno_test/realm_sync.txtar index 3d27ab4fde0..c93e6d86e8f 100644 --- a/gnovm/cmd/gno/testdata/gno_test/realm_sync.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/realm_sync.txtar @@ -10,8 +10,8 @@ stderr 'ok \. \d\.\d\ds' cmp x_filetest.gno x_filetest.gno.golden -- x_filetest.gno -- -// PKGPATH: gno.land/r/x -package x +// PKGPATH: gno.land/r/xx +package xx var x int @@ -21,10 +21,9 @@ func main() { // Realm: // xxx - -- x_filetest.gno.golden -- -// PKGPATH: gno.land/r/x -package x +// PKGPATH: gno.land/r/xx +package xx var x int @@ -33,11 +32,11 @@ func main() { } // Realm: -// switchrealm["gno.land/r/x"] -// u[58cde29876a8d185e30c727361981efb068f4726:2]={ +// switchrealm["gno.land/r/xx"] +// u[aea84df38908f9569d0f552575606e6e6e7e22dd:2]={ // "Blank": {}, // "ObjectInfo": { -// "ID": "58cde29876a8d185e30c727361981efb068f4726:2", +// "ID": "aea84df38908f9569d0f552575606e6e6e7e22dd:2", // "IsEscaped": true, // "ModTime": "3", // "RefCount": "2" @@ -50,7 +49,7 @@ func main() { // "Column": "0", // "File": "", // "Line": "0", -// "PkgPath": "gno.land/r/x" +// "PkgPath": "gno.land/r/xx" // } // }, // "Values": [ @@ -72,22 +71,22 @@ func main() { // "Closure": { // "@type": "/gno.RefValue", // "Escaped": true, -// "ObjectID": "58cde29876a8d185e30c727361981efb068f4726:3" +// "ObjectID": "aea84df38908f9569d0f552575606e6e6e7e22dd:3" // }, -// "FileName": "main.gno", +// "FileName": "x.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", // "NativePkg": "", -// "PkgPath": "gno.land/r/x", +// "PkgPath": "gno.land/r/xx", // "Source": { // "@type": "/gno.RefNode", // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "x.gno", // "Line": "6", -// "PkgPath": "gno.land/r/x" +// "PkgPath": "gno.land/r/xx" // } // }, // "Type": { @@ -99,4 +98,3 @@ func main() { // } // ] // } - diff --git a/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar b/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar deleted file mode 100644 index 6099788a9a1..00000000000 --- a/gnovm/cmd/gno/testdata/gno_test/test_with-native-fallback.txtar +++ /dev/null @@ -1,32 +0,0 @@ -# Test native lib - -! gno test -v . - -! stdout .+ -stderr 'panic: unknown import path net \[recovered\]' -stderr ' panic: gno.land/r/\w{8}/contract.gno:3:8: unknown import path net' - -gno test -v --with-native-fallback . - -! stdout .+ -stderr '=== RUN TestFoo' -stderr '--- PASS: TestFoo' - --- contract.gno -- -package contract - -import "net" - -func Foo() { - _ = net.IPv4 -} - --- contract_test.gno -- -package contract - -import "testing" - -func TestFoo(t *testing.T) { - Foo() -} - diff --git a/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar b/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar deleted file mode 100644 index 37ef68f3d91..00000000000 --- a/gnovm/cmd/gno/testdata/gno_test/unknow_lib.txtar +++ /dev/null @@ -1,32 +0,0 @@ -# Test unknow lib - -! gno test -v . - -! stdout .+ -stderr 'panic: unknown import path foobarbaz \[recovered\]' -stderr ' panic: gno.land/r/\w{8}/contract.gno:3:8: unknown import path foobarbaz' - -! gno test -v --with-native-fallback . - -! stdout .+ -stderr 'panic: unknown import path foobarbaz \[recovered\]' -stderr ' panic: gno.land/r/\w{8}/contract.gno:3:8: unknown import path foobarbaz' - --- contract.gno -- -package contract - -import "foobarbaz" - -func Foo() { - _ = foobarbaz.Gnognogno -} - --- contract_test.gno -- -package contract - -import "testing" - -func TestFoo(t *testing.T) { - Foo() -} - diff --git a/gnovm/cmd/gno/testdata/gno_test/unknown_package.txtar b/gnovm/cmd/gno/testdata/gno_test/unknown_package.txtar new file mode 100644 index 00000000000..0611d3440a4 --- /dev/null +++ b/gnovm/cmd/gno/testdata/gno_test/unknown_package.txtar @@ -0,0 +1,24 @@ +# Test for loading an unknown package + +! gno test -v . + +! stdout .+ +stderr 'contract.gno:3:8: unknown import path foobarbaz' + +-- contract.gno -- +package contract + +import "foobarbaz" + +func Foo() { + _ = foobarbaz.Gnognogno +} + +-- contract_test.gno -- +package contract + +import "testing" + +func TestFoo(t *testing.T) { + Foo() +} diff --git a/gnovm/cmd/gno/testdata/gno_test/valid_filetest.txtar b/gnovm/cmd/gno/testdata/gno_test/valid_filetest.txtar index 02ae3f72304..4e24ad9ab08 100644 --- a/gnovm/cmd/gno/testdata/gno_test/valid_filetest.txtar +++ b/gnovm/cmd/gno/testdata/gno_test/valid_filetest.txtar @@ -7,7 +7,7 @@ stderr 'ok \. \d\.\d\ds' gno test -v . -! stdout .+ +stdout 'test' stderr '=== RUN file/valid_filetest.gno' stderr '--- PASS: file/valid_filetest.gno \(\d\.\d\ds\)' stderr 'ok \. \d\.\d\ds' diff --git a/gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_build_error.txtar b/gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_build_error.txtar index d21390f9472..145fe796c09 100644 --- a/gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_build_error.txtar +++ b/gnovm/cmd/gno/testdata/gno_transpile/gobuild_flag_build_error.txtar @@ -1,10 +1,11 @@ # Run gno transpile with -gobuild flag +# The error messages changed sometime in go1.23, so this avoids errors ! gno transpile -gobuild . ! stdout .+ -stderr '^main.gno:4:6: x declared and not used$' -stderr '^main.gno:5:6: y declared and not used$' +stderr '^main.gno:4:6: .*declared and not used' +stderr '^main.gno:5:6: .*declared and not used' stderr '^2 transpile error\(s\)$' cmp main.gno.gen.go main.gno.gen.go.golden diff --git a/gnovm/cmd/gno/util.go b/gnovm/cmd/gno/util.go index 90aedd5d27a..697aa94b3c6 100644 --- a/gnovm/cmd/gno/util.go +++ b/gnovm/cmd/gno/util.go @@ -338,17 +338,3 @@ func copyFile(src, dst string) error { return nil } - -// Adapted from https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format/ -func prettySize(nb int64) string { - const unit = 1000 - if nb < unit { - return fmt.Sprintf("%d", nb) - } - div, exp := int64(unit), 0 - for n := nb / unit; n >= unit; n /= unit { - div *= unit - exp++ - } - return fmt.Sprintf("%.1f%c", float64(nb)/float64(div), "kMGTPE"[exp]) -} diff --git a/gnovm/pkg/gnolang/debugger_test.go b/gnovm/pkg/gnolang/debugger_test.go index 63a3ee74675..926ff0595e6 100644 --- a/gnovm/pkg/gnolang/debugger_test.go +++ b/gnovm/pkg/gnolang/debugger_test.go @@ -12,7 +12,7 @@ import ( "github.com/gnolang/gno/gnovm/pkg/gnoenv" "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/tests" + "github.com/gnolang/gno/gnovm/pkg/test" ) type dtest struct{ in, out string } @@ -24,17 +24,12 @@ type writeNopCloser struct{ io.Writer } func (writeNopCloser) Close() error { return nil } // TODO (Marc): move evalTest to gnovm/tests package and remove code duplicates -func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { +func evalTest(debugAddr, in, file string) (out, err string) { bout := bytes.NewBufferString("") berr := bytes.NewBufferString("") stdin := bytes.NewBufferString(in) stdout := writeNopCloser{bout} stderr := writeNopCloser{berr} - debug := in != "" || debugAddr != "" - mode := tests.ImportModeStdlibsPreferred - if strings.HasSuffix(file, "_native.gno") { - mode = tests.ImportModeNativePreferred - } defer func() { if r := recover(); r != nil { @@ -44,7 +39,7 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { err = strings.TrimSpace(strings.ReplaceAll(err, "../../tests/files/", "files/")) }() - testStore := tests.TestStore(gnoenv.RootDir(), "../../tests/files", stdin, stdout, stderr, mode) + _, testStore := test.Store(gnoenv.RootDir(), false, stdin, stdout, stderr) f := gnolang.MustReadFile(file) @@ -53,23 +48,11 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { Input: stdin, Output: stdout, Store: testStore, - Context: tests.TestContext(string(f.PkgName), nil), - Debug: debug, + Context: test.Context(string(f.PkgName), nil), + Debug: true, }) defer m.Release() - defer func() { - if r := recover(); r != nil { - switch r.(type) { - case gnolang.UnhandledPanicError: - stacktrace = m.ExceptionsStacktrace() - default: - stacktrace = m.Stacktrace().String() - } - stacktrace = strings.TrimSpace(strings.ReplaceAll(stacktrace, "../../tests/files/", "files/")) - panic(r) - } - }() if debugAddr != "" { if e := m.Debugger.Serve(debugAddr); e != nil { @@ -81,7 +64,7 @@ func evalTest(debugAddr, in, file string) (out, err, stacktrace string) { m.RunFiles(f) ex, _ := gnolang.ParseExpr("main()") m.Eval(ex) - out, err, stacktrace = bout.String(), berr.String(), m.ExceptionsStacktrace() + out, err = bout.String(), berr.String() return } @@ -90,7 +73,7 @@ func runDebugTest(t *testing.T, targetPath string, tests []dtest) { for _, test := range tests { t.Run("", func(t *testing.T) { - out, err, _ := evalTest("", test.in, targetPath) + out, err := evalTest("", test.in, targetPath) t.Log("in:", test.in, "out:", out, "err:", err) if !strings.Contains(out, test.out) { t.Errorf("unexpected output\nwant\"%s\"\n got \"%s\"", test.out, out) @@ -206,7 +189,7 @@ func TestRemoteDebug(t *testing.T) { } func TestRemoteError(t *testing.T) { - _, err, _ := evalTest(":xxx", "", debugTarget) + _, err := evalTest(":xxx", "", debugTarget) t.Log("err:", err) if !strings.Contains(err, "tcp/xxx: unknown port") && !strings.Contains(err, "tcp/xxx: nodename nor servname provided, or not known") { diff --git a/gnovm/pkg/gnolang/eval_test.go b/gnovm/pkg/gnolang/eval_test.go deleted file mode 100644 index 9b83d673767..00000000000 --- a/gnovm/pkg/gnolang/eval_test.go +++ /dev/null @@ -1,132 +0,0 @@ -package gnolang_test - -import ( - "io/fs" - "os" - "path/filepath" - "regexp" - "sort" - "strings" - "testing" -) - -func TestEvalFiles(t *testing.T) { - dir := "../../tests/files" - fsys := os.DirFS(dir) - err := fs.WalkDir(fsys, ".", func(path string, de fs.DirEntry, err error) error { - switch { - case err != nil: - return err - case path == "extern": - return fs.SkipDir - case de.IsDir(): - return nil - } - - fullPath := filepath.Join(dir, path) - wantOut, wantErr, wantStacktrace, ok := testData(fullPath) - if !ok { - return nil - } - - t.Run(path, func(t *testing.T) { - out, err, stacktrace := evalTest("", "", fullPath) - - if wantErr != "" && !strings.Contains(err, wantErr) || - wantErr == "" && err != "" { - t.Fatalf("unexpected error\nWant: %s\n Got: %s", wantErr, err) - } - - if wantStacktrace != "" && !strings.Contains(stacktrace, wantStacktrace) { - t.Fatalf("unexpected stacktrace\nWant: %s\n Got: %s", wantStacktrace, stacktrace) - } - if wantOut != "" && strings.TrimSpace(out) != strings.TrimSpace(wantOut) { - t.Fatalf("unexpected output\nWant: \"%s\"\n Got: \"%s\"", wantOut, out) - } - }) - - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -// testData returns the expected output and error string, and true if entry is valid. -func testData(name string) (testOut, testErr, testStacktrace string, ok bool) { - if !strings.HasSuffix(name, ".gno") || strings.HasSuffix(name, "_long.gno") { - return - } - buf, err := os.ReadFile(name) - if err != nil { - return - } - str := string(buf) - if strings.Contains(str, "// PKGPATH:") { - return - } - res := commentFrom(str, []string{ - "// Output:", - "// Error:", - "// Stacktrace:", - }) - - return res[0], res[1], res[2], true -} - -type directive struct { - delim string - res string - index int -} - -// (?m) makes ^ and $ match start/end of string. -// Used to substitute from a comment all the //. -// Using a regex allows us to parse lines only containing "//" as an empty line. -var reCommentPrefix = regexp.MustCompile("(?m)^//(?: |$)") - -// commentFrom returns the comments from s that are between the delimiters. -// delims is a list of delimiters like "// Output:", which should be on a -// single line to mark the beginning of a directive. -// The return value is the content of each directive, matching the indexes -// of delims, ie. len(result) == len(delims). -func commentFrom(s string, delims []string) []string { - directives := make([]directive, len(delims)) - directivesFound := make([]*directive, 0, len(delims)) - - // Find directives - for i, delim := range delims { - // must find delim isolated on one line - delim = "\n" + delim + "\n" - index := strings.Index(s, delim) - directives[i] = directive{delim: delim, index: index} - if index >= 0 { - directivesFound = append(directivesFound, &directives[i]) - } - } - sort.Slice(directivesFound, func(i, j int) bool { - return directivesFound[i].index < directivesFound[j].index - }) - - for i := range directivesFound { - next := len(s) - if i != len(directivesFound)-1 { - next = directivesFound[i+1].index - } - - // Mark beginning of directive content from the line after the directive. - contentStart := directivesFound[i].index + len(directivesFound[i].delim) - content := s[contentStart:next] - - // Remove comment prefixes. - parsed := reCommentPrefix.ReplaceAllLiteralString(content, "") - directivesFound[i].res = strings.TrimSuffix(parsed, "\n") - } - - res := make([]string, len(directives)) - for i, d := range directives { - res[i] = d.res - } - - return res -} diff --git a/gnovm/pkg/gnolang/files_test.go b/gnovm/pkg/gnolang/files_test.go new file mode 100644 index 00000000000..f1bc87d21d8 --- /dev/null +++ b/gnovm/pkg/gnolang/files_test.go @@ -0,0 +1,141 @@ +package gnolang_test + +import ( + "bytes" + "flag" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/gnovm/pkg/test" + "github.com/stretchr/testify/require" +) + +var withSync = flag.Bool("update-golden-tests", false, "rewrite tests updating Realm: and Output: with new values where changed") + +type nopReader struct{} + +func (nopReader) Read(p []byte) (int, error) { return 0, io.EOF } + +// TestFiles tests all the files in "gnovm/tests/files". +// +// Cheatsheet: +// +// fail on the first test: +// go test -run TestFiles -failfast +// run a specific test: +// go test -run TestFiles/addr0b +// fix a specific test: +// go test -run TestFiles/'^bin1.gno' -short -v -update-golden-tests . +func TestFiles(t *testing.T) { + rootDir, err := filepath.Abs("../../../") + require.NoError(t, err) + + opts := &test.TestOptions{ + RootDir: rootDir, + Output: io.Discard, + Error: io.Discard, + Sync: *withSync, + } + opts.BaseStore, opts.TestStore = test.Store( + rootDir, true, + nopReader{}, opts.WriterForStore(), io.Discard, + ) + + dir := "../../tests/" + fsys := os.DirFS(dir) + err = fs.WalkDir(fsys, "files", func(path string, de fs.DirEntry, err error) error { + switch { + case err != nil: + return err + case path == "files/extern": + return fs.SkipDir + case de.IsDir(): + return nil + } + subTestName := path[len("files/"):] + if strings.HasSuffix(path, "_long.gno") && testing.Short() { + t.Run(subTestName, func(t *testing.T) { + t.Skip("skipping in -short") + }) + return nil + } + + content, err := fs.ReadFile(fsys, path) + if err != nil { + return err + } + + var criticalError error + t.Run(subTestName, func(t *testing.T) { + changed, err := opts.RunFiletest(path, content) + if err != nil { + t.Fatal(err.Error()) + } + if changed != "" { + err = os.WriteFile(filepath.Join(dir, path), []byte(changed), de.Type()) + if err != nil { + criticalError = fmt.Errorf("could not fix golden file: %w", err) + } + } + }) + + return criticalError + }) + if err != nil { + t.Fatal(err) + } +} + +// TestStdlibs tests all the standard library packages. +func TestStdlibs(t *testing.T) { + rootDir, err := filepath.Abs("../../../") + require.NoError(t, err) + + var capture bytes.Buffer + out := io.Writer(&capture) + if testing.Verbose() { + out = os.Stdout + } + opts := test.NewTestOptions(rootDir, nopReader{}, out, out) + opts.Verbose = true + + dir := "../../stdlibs/" + fsys := os.DirFS(dir) + err = fs.WalkDir(fsys, ".", func(path string, de fs.DirEntry, err error) error { + switch { + case err != nil: + return err + case !de.IsDir() || path == ".": + return nil + } + + fp := filepath.Join(dir, path) + memPkg := gnolang.ReadMemPackage(fp, path) + t.Run(strings.ReplaceAll(memPkg.Path, "/", "-"), func(t *testing.T) { + if testing.Short() { + switch memPkg.Path { + case "bytes", "strconv", "regexp/syntax": + t.Skip("Skipped because of -short, and this stdlib is very long currently.") + } + } + err := test.Test(memPkg, "", opts) + if !testing.Verbose() { + t.Log(capture.String()) + } + if err != nil { + t.Error(err) + } + }) + + return nil + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index fe92f5bcd23..5a39c76b5e1 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -83,11 +83,6 @@ func go2GnoBaseType(rt reflect.Type) Type { } } -// Implements Store. -func (ds *defaultStore) SetStrictGo2GnoMapping(strict bool) { - ds.go2gnoStrict = strict -} - // Implements Store. // See go2GnoValue2(). Like go2GnoType() but also converts any // top-level complex types (or pointers to them). The result gets @@ -109,54 +104,9 @@ func (ds *defaultStore) Go2GnoType(rt reflect.Type) (t Type) { // wrap t with declared type. pkgPath := rt.PkgPath() if pkgPath != "" { - // mappings have been removed, so for any non-builtin type in strict mode, - // this will panic. - if ds.go2gnoStrict { - // mapping failed and strict: error. - gokey := pkgPath + "." + rt.Name() - panic(fmt.Sprintf("native type does not exist for %s", gokey)) - } - - // generate a new gno type for testing. - mtvs := []TypedValue(nil) - if t.Kind() == InterfaceKind { - // methods already set on t.Methods. - // *DT.Methods not used in Go for interfaces. - } else { - prt := rt - if rt.Kind() != reflect.Ptr { - // NOTE: go reflect requires ptr kind - // for methods with ptr receivers, - // whereas gno methods are all - // declared on the *DeclaredType. - prt = reflect.PointerTo(rt) - } - nm := prt.NumMethod() - mtvs = make([]TypedValue, nm) - for i := 0; i < nm; i++ { - mthd := prt.Method(i) - ft := ds.go2GnoFuncType(mthd.Type) - fv := &FuncValue{ - Type: ft, - IsMethod: true, - Source: nil, - Name: Name(mthd.Name), - Closure: nil, - PkgPath: pkgPath, - body: nil, // XXX - nativeBody: nil, - } - mtvs[i] = TypedValue{T: ft, V: fv} - } - } - dt := &DeclaredType{ - PkgPath: pkgPath, - Name: Name(rt.Name()), - Base: t, - Methods: mtvs, - } - dt.Seal() - t = dt + // mappings have been removed, so this should never happen. + gokey := pkgPath + "." + rt.Name() + panic(fmt.Sprintf("native type does not exist for %s", gokey)) } // memoize t to cache. if debug { @@ -1230,34 +1180,6 @@ func gno2GoValue(tv *TypedValue, rv reflect.Value) (ret reflect.Value) { // ---------------------------------------- // PackageNode methods -func (x *PackageNode) DefineGoNativeType(rt reflect.Type) { - if debug { - debug.Printf("*PackageNode.DefineGoNativeType(%s)\n", rt.String()) - } - pkgp := rt.PkgPath() - if pkgp == "" { - // DefineGoNativeType can only work with defined exported types. - // Unexported types should be composed, and primitive types - // should just use Gno types. - panic(fmt.Sprintf( - "reflect.Type %s has no package path", - rt.String())) - } - name := rt.Name() - if name == "" { - panic(fmt.Sprintf( - "reflect.Type %s is not named", - rt.String())) - } - if rt.PkgPath() == "" { - panic(fmt.Sprintf( - "reflect.Type %s is not defined/exported", - rt.String())) - } - nt := &NativeType{Type: rt} - x.Define(Name(name), asValue(nt)) -} - func (x *PackageNode) DefineGoNativeValue(name Name, nv interface{}) { x.defineGoNativeValue(false, name, nv) } diff --git a/gnovm/pkg/gnolang/gonative_test.go b/gnovm/pkg/gnolang/gonative_test.go deleted file mode 100644 index fa5415a8068..00000000000 --- a/gnovm/pkg/gnolang/gonative_test.go +++ /dev/null @@ -1,149 +0,0 @@ -package gnolang - -import ( - "bytes" - "fmt" - "reflect" - "testing" - - "github.com/gnolang/gno/tm2/pkg/crypto" - "github.com/stretchr/testify/assert" -) - -// args is an even number of elements, -// the even index items are package nodes, -// and the odd index items are corresponding package values. -func gonativeTestStore(args ...interface{}) Store { - store := NewStore(nil, nil, nil) - store.SetPackageGetter(func(pkgPath string, _ Store) (*PackageNode, *PackageValue) { - for i := 0; i < len(args)/2; i++ { - pn := args[i*2].(*PackageNode) - pv := args[i*2+1].(*PackageValue) - if pkgPath == pv.PkgPath { - return pn, pv - } - } - return nil, nil - }) - store.SetStrictGo2GnoMapping(false) - return store -} - -type Foo struct { - A int - B int32 - C int64 - D string -} - -func TestGoNativeDefine(t *testing.T) { - // Create package foo and define Foo. - pkg := NewPackageNode("foo", "test.foo", nil) - rt := reflect.TypeOf(Foo{}) - pkg.DefineGoNativeType(rt) - nt := pkg.GetValueRef(nil, Name("Foo"), true).GetType().(*NativeType) - assert.Equal(t, rt, nt.Type) - path := pkg.GetPathForName(nil, Name("Foo")) - assert.Equal(t, uint8(1), path.Depth) - assert.Equal(t, uint16(0), path.Index) - pv := pkg.NewPackage() - nt = pv.GetBlock(nil).GetPointerTo(nil, path).TV.GetType().(*NativeType) - assert.Equal(t, rt, nt.Type) - store := gonativeTestStore(pkg, pv) - - // Import above package and evaluate foo.Foo. - m := NewMachineWithOptions(MachineOptions{ - PkgPath: "test", - Store: store, - }) - m.RunDeclaration(ImportD("foo", "test.foo")) - tvs := m.Eval(Sel(Nx("foo"), "Foo")) - assert.Equal(t, 1, len(tvs)) - assert.Equal(t, nt, tvs[0].V.(TypeValue).Type) -} - -func TestGoNativeDefine2(t *testing.T) { - // Create package foo and define Foo. - pkg := NewPackageNode("foo", "test.foo", nil) - rt := reflect.TypeOf(Foo{}) - pkg.DefineGoNativeType(rt) - pv := pkg.NewPackage() - store := gonativeTestStore(pkg, pv) - - // Import above package and run file. - out := new(bytes.Buffer) - m := NewMachineWithOptions(MachineOptions{ - PkgPath: "main", - Output: out, - Store: store, - }) - - c := `package main -import foo "test.foo" -func main() { - f := foo.Foo{A:1} - println("A:", f.A) - println("B:", f.B) - println("C:", f.C) - println("D:", f.D) -}` - n := MustParseFile("main.go", c) - m.RunFiles(n) - m.RunMain() - // weird `+` is used to place a space, without having editors strip it away. - assert.Equal(t, `A: 1 -B: 0 -C: 0 -D: `+` -`, string(out.Bytes())) -} - -func TestGoNativeDefine3(t *testing.T) { - t.Parallel() - - // Create package foo and define Foo. - out := new(bytes.Buffer) - pkg := NewPackageNode("foo", "test.foo", nil) - pkg.DefineGoNativeType(reflect.TypeOf(Foo{})) - pkg.DefineGoNativeValue("PrintFoo", func(f Foo) { - out.Write([]byte(fmt.Sprintf("A: %v\n", f.A))) - out.Write([]byte(fmt.Sprintf("B: %v\n", f.B))) - out.Write([]byte(fmt.Sprintf("C: %v\n", f.C))) - out.Write([]byte(fmt.Sprintf("D: %v\n", f.D))) - }) - pv := pkg.NewPackage() - store := gonativeTestStore(pkg, pv) - - // Import above package and run file. - m := NewMachineWithOptions(MachineOptions{ - PkgPath: "main", - Output: out, - Store: store, - }) - - c := `package main -import foo "test.foo" -func main() { - f := foo.Foo{A:1} - foo.PrintFoo(f) -}` - n := MustParseFile("main.go", c) - m.RunFiles(n) - m.RunMain() - assert.Equal(t, `A: 1 -B: 0 -C: 0 -D: `+` -`, out.String()) -} - -func TestCrypto(t *testing.T) { - t.Parallel() - - addr := crypto.Address{} - store := gonativeTestStore() - tv := Go2GnoValue(nilAllocator, store, reflect.ValueOf(addr)) - assert.Equal(t, - `(array[0x0000000000000000000000000000000000000000] github.com/gnolang/gno/tm2/pkg/crypto.Address)`, - tv.String()) -} diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index e341ef8e9f1..4f4c7c188f3 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -3,7 +3,6 @@ package gnolang // XXX rename file to machine.go. import ( - "encoding/json" "fmt" "io" "reflect" @@ -11,7 +10,6 @@ import ( "strconv" "strings" "sync" - "testing" "github.com/gnolang/overflow" @@ -299,7 +297,7 @@ func (m *Machine) runMemPackage(memPkg *gnovm.MemPackage, save, overrides bool) } m.SetActivePackage(pv) // run files. - updates := m.RunFileDecls(files.Files...) + updates := m.runFileDecls(files.Files...) // save package value and mempackage. // XXX save condition will be removed once gonative is removed. var throwaway *Realm @@ -400,103 +398,6 @@ func destar(x Expr) Expr { return x } -// Tests all test files in a mempackage. -// Assumes that the importing of packages is handled elsewhere. -// The resulting package value and node become injected with TestMethods and -// other declarations, so it is expected that non-test code will not be run -// afterwards from the same store. -func (m *Machine) TestMemPackage(t *testing.T, memPkg *gnovm.MemPackage) { - defer m.injectLocOnPanic() - DisableDebug() - fmt.Println("DEBUG DISABLED (FOR TEST DEPENDENCIES INIT)") - // parse test files. - tfiles, itfiles := ParseMemPackageTests(memPkg) - { // first, tfiles which run in the same package. - pv := m.Store.GetPackage(memPkg.Path, false) - pvBlock := pv.GetBlock(m.Store) - pvSize := len(pvBlock.Values) - m.SetActivePackage(pv) - // run test files. - m.RunFiles(tfiles.Files...) - // run all tests in test files. - for i := pvSize; i < len(pvBlock.Values); i++ { - tv := pvBlock.Values[i] - m.TestFunc(t, tv) - } - } - { // run all (import) tests in test files. - pn := NewPackageNode(Name(memPkg.Name+"_test"), memPkg.Path+"_test", itfiles) - pv := pn.NewPackage() - m.Store.SetBlockNode(pn) - m.Store.SetCachePackage(pv) - pvBlock := pv.GetBlock(m.Store) - m.SetActivePackage(pv) - m.RunFiles(itfiles.Files...) - pn.PrepareNewValues(pv) - EnableDebug() - fmt.Println("DEBUG ENABLED") - for i := 0; i < len(pvBlock.Values); i++ { - tv := pvBlock.Values[i] - m.TestFunc(t, tv) - } - } -} - -// TestFunc calls tv with testing.RunTest, if tv is a function with a name that -// starts with `Test`. -func (m *Machine) TestFunc(t *testing.T, tv TypedValue) { - if !(tv.T.Kind() == FuncKind && - strings.HasPrefix(string(tv.V.(*FuncValue).Name), "Test")) { - return // not a test function. - } - // XXX ensure correct func type. - name := string(tv.V.(*FuncValue).Name) - // prefetch the testing package. - testingpv := m.Store.GetPackage("testing", false) - testingtv := TypedValue{T: gPackageType, V: testingpv} - testingcx := &ConstExpr{TypedValue: testingtv} - - t.Run(name, func(t *testing.T) { - defer m.injectLocOnPanic() - x := Call( - Sel(testingcx, "RunTest"), // Call testing.RunTest - Str(name), // First param, the name of the test - X("true"), // Second Param, verbose bool - &CompositeLitExpr{ // Third param, the testing.InternalTest - Type: Sel(testingcx, "InternalTest"), - Elts: KeyValueExprs{ - {Key: X("Name"), Value: Str(name)}, - {Key: X("F"), Value: X(name)}, - }, - }, - ) - res := m.Eval(x) - ret := res[0].GetString() - if ret == "" { - t.Errorf("failed to execute unit test: %q", name) - return - } - - // mirror of stdlibs/testing.Report - var report struct { - Skipped bool - Failed bool - } - err := json.Unmarshal([]byte(ret), &report) - if err != nil { - t.Errorf("failed to parse test output %q", name) - return - } - - switch { - case report.Skipped: - t.SkipNow() - case report.Failed: - t.Fail() - } - }) -} - // Stacktrace returns the stack trace of the machine. // It collects the executions and frames from the machine's frames and statements. func (m *Machine) Stacktrace() (stacktrace Stacktrace) { @@ -534,58 +435,6 @@ func (m *Machine) Stacktrace() (stacktrace Stacktrace) { return } -// in case of panic, inject location information to exception. -func (m *Machine) injectLocOnPanic() { - if r := recover(); r != nil { - // Show last location information. - // First, determine the line number of expression or statement if any. - lastLine := 0 - lastColumn := 0 - if len(m.Exprs) > 0 { - for i := len(m.Exprs) - 1; i >= 0; i-- { - expr := m.Exprs[i] - if expr.GetLine() > 0 { - lastLine = expr.GetLine() - lastColumn = expr.GetColumn() - break - } - } - } - if lastLine == 0 && len(m.Stmts) > 0 { - for i := len(m.Stmts) - 1; i >= 0; i-- { - stmt := m.Stmts[i] - if stmt.GetLine() > 0 { - lastLine = stmt.GetLine() - lastColumn = stmt.GetColumn() - break - } - } - } - // Append line number to block location. - lastLoc := Location{} - for i := len(m.Blocks) - 1; i >= 0; i-- { - block := m.Blocks[i] - src := block.GetSource(m.Store) - loc := src.GetLocation() - if !loc.IsZero() { - lastLoc = loc - if lastLine > 0 { - lastLoc.Line = lastLine - lastLoc.Column = lastColumn - } - break - } - } - // wrap panic with location information. - if !lastLoc.IsZero() { - fmt.Printf("%s: %v\n", lastLoc.String(), r) - panic(errors.Wrap(r, fmt.Sprintf("location: %s", lastLoc.String()))) - } else { - panic(r) - } - } -} - // Convenience for tests. // Production must not use this, because realm package init // must happen after persistence and realm finalization, @@ -602,10 +451,6 @@ func (m *Machine) RunFiles(fns ...*FileNode) { // Add files to the package's *FileSet and run decls in them. // This will also run each init function encountered. // Returns the updated typed values of package. -func (m *Machine) RunFileDecls(fns ...*FileNode) []TypedValue { - return m.runFileDecls(fns...) -} - func (m *Machine) runFileDecls(fns ...*FileNode) []TypedValue { // Files' package names must match the machine's active one. // if there is one. diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 45062f8e14c..dcc1ad41739 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -13,7 +13,6 @@ import ( "strings" "github.com/gnolang/gno/gnovm" - "github.com/gnolang/gno/tm2/pkg/errors" "go.uber.org/multierr" ) @@ -1257,38 +1256,6 @@ func ParseMemPackage(memPkg *gnovm.MemPackage) (fset *FileSet) { return fset } -func ParseMemPackageTests(memPkg *gnovm.MemPackage) (tset, itset *FileSet) { - tset = &FileSet{} - itset = &FileSet{} - for _, mfile := range memPkg.Files { - if !strings.HasSuffix(mfile.Name, ".gno") { - continue // skip this file. - } - n, err := ParseFile(mfile.Name, mfile.Body) - if err != nil { - panic(errors.Wrap(err, "parsing file "+mfile.Name)) - } - if n == nil { - panic("should not happen") - } - if strings.HasSuffix(mfile.Name, "_test.gno") { - // add test file. - if memPkg.Name+"_test" == string(n.PkgName) { - itset.AddFiles(n) - } else { - tset.AddFiles(n) - } - } else if memPkg.Name == string(n.PkgName) { - // skip package file. - } else { - panic(fmt.Sprintf( - "expected package name [%s] or [%s_test] but got [%s] file [%s]", - memPkg.Name, memPkg.Name, n.PkgName, mfile)) - } - } - return tset, itset -} - func (fs *FileSet) AddFiles(fns ...*FileNode) { fs.Files = append(fs.Files, fns...) } diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 7198d4f6a98..4b556604f0b 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -358,6 +358,11 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { func doRecover(stack []BlockNode, n Node) { if r := recover(); r != nil { + if _, ok := r.(*PreprocessError); ok { + // re-panic directly if this is a PreprocessError already. + panic(r) + } + // before re-throwing the error, append location information to message. last := stack[len(stack)-1] loc := last.GetLocation() @@ -4018,23 +4023,7 @@ func checkIntegerKind(xt Type) { // preprocess-able before other file-level declarations are // preprocessed). func predefineNow(store Store, last BlockNode, d Decl) (Decl, bool) { - defer func() { - if r := recover(); r != nil { - // before re-throwing the error, append location information to message. - loc := last.GetLocation() - if nline := d.GetLine(); nline > 0 { - loc.Line = nline - loc.Column = d.GetColumn() - } - if rerr, ok := r.(error); ok { - // NOTE: gotuna/gorilla expects error exceptions. - panic(errors.Wrap(rerr, loc.String())) - } else { - // NOTE: gotuna/gorilla expects error exceptions. - panic(fmt.Errorf("%s: %v", loc.String(), r)) - } - } - }() + defer doRecover([]BlockNode{last}, d) stack := &[]Name{} return predefineNow2(store, last, d, stack) } @@ -4099,10 +4088,10 @@ func predefineNow2(store Store, last BlockNode, d Decl, stack *[]Name) (Decl, bo // check base type of receiver type, should not be pointer type or interface type assertValidReceiverType := func(t Type) { if _, ok := t.(*PointerType); ok { - panic(fmt.Sprintf("invalid receiver type %v (base type is pointer type)\n", rt)) + panic(fmt.Sprintf("invalid receiver type %v (base type is pointer type)", rt)) } if _, ok := t.(*InterfaceType); ok { - panic(fmt.Sprintf("invalid receiver type %v (base type is interface type)\n", rt)) + panic(fmt.Sprintf("invalid receiver type %v (base type is interface type)", rt)) } } diff --git a/gnovm/pkg/gnolang/preprocess_test.go b/gnovm/pkg/gnolang/preprocess_test.go deleted file mode 100644 index 53ad97dd972..00000000000 --- a/gnovm/pkg/gnolang/preprocess_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package gnolang - -import ( - "fmt" - "reflect" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestPreprocess_BinaryExpressionOneNative(t *testing.T) { - pn := NewPackageNode("time", "time", nil) - pn.DefineGoNativeConstValue("Millisecond", time.Millisecond) - pn.DefineGoNativeConstValue("Second", time.Second) - pn.DefineGoNativeType(reflect.TypeOf(time.Duration(0))) - pv := pn.NewPackage() - store := gonativeTestStore(pn, pv) - store.SetBlockNode(pn) - - const src = `package main - import "time" -func main() { - var a int64 = 2 - println(time.Second * a) - -}` - n := MustParseFile("main.go", src) - - defer func() { - err := recover() - assert.Contains(t, fmt.Sprint(err), "incompatible operands in binary expression") - }() - initStaticBlocks(store, pn, n) - Preprocess(store, pn, n) -} - -func TestPreprocess_BinaryExpressionBothNative(t *testing.T) { - pn := NewPackageNode("time", "time", nil) - pn.DefineGoNativeConstValue("March", time.March) - pn.DefineGoNativeConstValue("Wednesday", time.Wednesday) - pn.DefineGoNativeType(reflect.TypeOf(time.Month(0))) - pn.DefineGoNativeType(reflect.TypeOf(time.Weekday(0))) - pv := pn.NewPackage() - store := gonativeTestStore(pn, pv) - store.SetBlockNode(pn) - - const src = `package main - import "time" -func main() { - println(time.March * time.Wednesday) - -}` - n := MustParseFile("main.go", src) - - defer func() { - err := recover() - assert.Contains(t, fmt.Sprint(err), "incompatible operands in binary expression") - }() - initStaticBlocks(store, pn, n) - Preprocess(store, pn, n) -} diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 9410eede29e..2c0ee05a1d7 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -51,7 +51,6 @@ type Store interface { GetBlockNodeSafe(Location) BlockNode SetBlockNode(BlockNode) // UNSTABLE - SetStrictGo2GnoMapping(bool) Go2GnoType(rt reflect.Type) Type GetAllocator() *Allocator NumMemPackages() int64 @@ -68,7 +67,6 @@ type Store interface { SetLogStoreOps(enabled bool) SprintStoreOps() string LogSwitchRealm(rlmpath string) // to mark change of realm boundaries - ClearCache() Print() } @@ -98,7 +96,6 @@ type defaultStore struct { pkgGetter PackageGetter // non-realm packages cacheNativeTypes map[reflect.Type]Type // reflect doc: reflect.Type are comparable nativeStore NativeStore // for injecting natives - go2gnoStrict bool // if true, native->gno type conversion must be registered. // transient opslog []StoreOp // for debugging and testing. @@ -120,7 +117,6 @@ func NewStore(alloc *Allocator, baseStore, iavlStore store.Store) *defaultStore pkgGetter: nil, cacheNativeTypes: make(map[reflect.Type]Type), nativeStore: nil, - go2gnoStrict: true, } InitStoreCaches(ds) return ds @@ -149,7 +145,6 @@ func (ds *defaultStore) BeginTransaction(baseStore, iavlStore store.Store) Trans pkgGetter: ds.pkgGetter, cacheNativeTypes: ds.cacheNativeTypes, nativeStore: ds.nativeStore, - go2gnoStrict: ds.go2gnoStrict, // transient current: nil, @@ -171,10 +166,6 @@ func (transactionStore) SetPackageGetter(pg PackageGetter) { panic("SetPackageGetter may not be called in a transaction store") } -func (transactionStore) ClearCache() { - panic("ClearCache may not be called in a transaction store") -} - // XXX: we should block Go2GnoType, because it uses a global cache map; // but it's called during preprocess and thus breaks some testing code. // let's wait until we remove Go2Gno entirely. @@ -187,10 +178,6 @@ func (transactionStore) SetNativeStore(ns NativeStore) { panic("SetNativeStore may not be called in a transaction store") } -func (transactionStore) SetStrictGo2GnoMapping(strict bool) { - panic("SetStrictGo2GnoMapping may not be called in a transaction store") -} - // CopyCachesFromStore allows to copy a store's internal object, type and // BlockNode cache into the dst store. // This is mostly useful for testing, where many stores have to be initialized. @@ -498,8 +485,7 @@ func (ds *defaultStore) SetCacheType(tt Type) { tid := tt.TypeID() if tt2, exists := ds.cacheTypes.Get(tid); exists { if tt != tt2 { - // NOTE: not sure why this would happen. - panic("should not happen") + panic(fmt.Sprintf("cannot re-register %q with different type", tid)) } else { // already set. } @@ -778,15 +764,6 @@ func (ds *defaultStore) LogSwitchRealm(rlmpath string) { StoreOp{Type: StoreOpSwitchRealm, RlmPath: rlmpath}) } -func (ds *defaultStore) ClearCache() { - ds.cacheObjects = make(map[ObjectID]Object) - ds.cacheTypes = txlog.GoMap[TypeID, Type](map[TypeID]Type{}) - ds.cacheNodes = txlog.GoMap[Location, BlockNode](map[Location]BlockNode{}) - ds.cacheNativeTypes = make(map[reflect.Type]Type) - // restore builtin types to cache. - InitStoreCaches(ds) -} - // for debugging func (ds *defaultStore) Print() { fmt.Println(colors.Yellow("//----------------------------------------")) diff --git a/gnovm/pkg/gnolang/store_test.go b/gnovm/pkg/gnolang/store_test.go index 40f84b65375..f7f03b947f6 100644 --- a/gnovm/pkg/gnolang/store_test.go +++ b/gnovm/pkg/gnolang/store_test.go @@ -58,9 +58,7 @@ func TestTransactionStore_blockedMethods(t *testing.T) { // These methods should panic as they modify store settings, which should // only be changed in the root store. assert.Panics(t, func() { transactionStore{}.SetPackageGetter(nil) }) - assert.Panics(t, func() { transactionStore{}.ClearCache() }) assert.Panics(t, func() { transactionStore{}.SetNativeStore(nil) }) - assert.Panics(t, func() { transactionStore{}.SetStrictGo2GnoMapping(false) }) } func TestCopyFromCachedStore(t *testing.T) { diff --git a/gnovm/pkg/repl/repl.go b/gnovm/pkg/repl/repl.go index e7b5ecea96f..b0944d21646 100644 --- a/gnovm/pkg/repl/repl.go +++ b/gnovm/pkg/repl/repl.go @@ -13,8 +13,9 @@ import ( "os" "text/template" + "github.com/gnolang/gno/gnovm/pkg/gnoenv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/tests" + "github.com/gnolang/gno/gnovm/pkg/test" ) const ( @@ -124,7 +125,8 @@ func NewRepl(opts ...ReplOption) *Repl { r.stderr = &b r.storeFunc = func() gno.Store { - return tests.TestStore("teststore", "", r.stdin, r.stdout, r.stderr, tests.ImportModeStdlibsOnly) + _, st := test.Store(gnoenv.RootDir(), false, r.stdin, r.stdout, r.stderr) + return st } for _, o := range opts { diff --git a/gnovm/pkg/test/filetest.go b/gnovm/pkg/test/filetest.go new file mode 100644 index 00000000000..12bc9ed7f28 --- /dev/null +++ b/gnovm/pkg/test/filetest.go @@ -0,0 +1,407 @@ +package test + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "regexp" + "runtime/debug" + "strconv" + "strings" + + "github.com/gnolang/gno/gnovm" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" + "github.com/gnolang/gno/tm2/pkg/std" + "github.com/pmezard/go-difflib/difflib" + "go.uber.org/multierr" +) + +// RunFiletest executes the program in source as a filetest. +// If opts.Sync is enabled, and the filetest's golden output has changed, +// the first string is set to the new generated content of the file. +func (opts *TestOptions) RunFiletest(filename string, source []byte) (string, error) { + opts.outWriter.w = opts.Output + + return opts.runFiletest(filename, source) +} + +var reEndOfLineSpaces = func() *regexp.Regexp { + re := regexp.MustCompile(" +\n") + re.Longest() + return re +}() + +func (opts *TestOptions) runFiletest(filename string, source []byte) (string, error) { + dirs, err := ParseDirectives(bytes.NewReader(source)) + if err != nil { + return "", fmt.Errorf("error parsing directives: %w", err) + } + + // Initialize Machine.Context and Machine.Alloc according to the input directives. + pkgPath := dirs.FirstDefault(DirectivePkgPath, "main") + coins, err := std.ParseCoins(dirs.FirstDefault(DirectiveSend, "")) + if err != nil { + return "", err + } + ctx := Context( + pkgPath, + coins, + ) + maxAllocRaw := dirs.FirstDefault(DirectiveMaxAlloc, "0") + maxAlloc, err := strconv.ParseInt(maxAllocRaw, 10, 64) + if err != nil { + return "", fmt.Errorf("could not parse MAXALLOC directive: %w", err) + } + + // Create machine for execution and run test + cw := opts.BaseStore.CacheWrap() + m := gno.NewMachineWithOptions(gno.MachineOptions{ + Output: &opts.outWriter, + Store: opts.TestStore.BeginTransaction(cw, cw), + Context: ctx, + MaxAllocBytes: maxAlloc, + }) + defer m.Release() + result := opts.runTest(m, pkgPath, filename, source) + + // updated tells whether the directives have been updated, and as such + // a new generated filetest should be returned. + // returnErr is used as the return value, and may be a MultiError if + // multiple mismatches occurred. + updated := false + var returnErr error + // match verifies the content against dir.Content; if different, + // either updates dir.Content (for opts.Sync) or appends a new returnErr. + match := func(dir *Directive, actual string) { + // Remove end-of-line spaces, as these are removed from `fmt` in the filetests anyway. + actual = reEndOfLineSpaces.ReplaceAllString(actual, "\n") + if dir.Content != actual { + if opts.Sync { + dir.Content = actual + updated = true + } else { + returnErr = multierr.Append( + returnErr, + fmt.Errorf("%s diff:\n%s", dir.Name, unifiedDiff(dir.Content, actual)), + ) + } + } + } + + // First, check if we have an error, whether we're supposed to get it. + if result.Error != "" { + // Ensure this error was supposed to happen. + errDirective := dirs.First(DirectiveError) + if errDirective == nil { + return "", fmt.Errorf("unexpected panic: %s\noutput:\n%s\nstack:\n%v", + result.Error, result.Output, string(result.GoPanicStack)) + } + + // The Error directive (and many others) will have one trailing newline, + // which is not in the output - so add it there. + match(errDirective, result.Error+"\n") + } else { + err = m.CheckEmpty() + if err != nil { + return "", fmt.Errorf("machine not empty after main: %w", err) + } + if gno.HasDebugErrors() { + return "", fmt.Errorf("got unexpected debug error(s): %v", gno.GetDebugErrors()) + } + } + + // Check through each directive and verify it against the values from the test. + for idx := range dirs { + dir := &dirs[idx] + switch dir.Name { + case DirectiveOutput: + if !strings.HasSuffix(result.Output, "\n") { + result.Output += "\n" + } + match(dir, result.Output) + case DirectiveRealm: + sops := m.Store.SprintStoreOps() + "\n" + match(dir, sops) + case DirectiveEvents: + events := m.Context.(*teststd.TestExecContext).EventLogger.Events() + evtjson, err := json.MarshalIndent(events, "", " ") + if err != nil { + panic(err) + } + evtstr := string(evtjson) + "\n" + match(dir, evtstr) + case DirectivePreprocessed: + pn := m.Store.GetBlockNode(gno.PackageNodeLocation(pkgPath)) + pre := pn.(*gno.PackageNode).FileSet.Files[0].String() + "\n" + match(dir, pre) + case DirectiveStacktrace: + match(dir, result.GnoStacktrace) + } + } + + if updated { // only true if sync == true + return dirs.FileTest(), returnErr + } + + return "", returnErr +} + +func unifiedDiff(wanted, actual string) string { + diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(wanted), + B: difflib.SplitLines(actual), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + if err != nil { + panic(fmt.Errorf("error generating unified diff: %w", err)) + } + return diff +} + +type runResult struct { + Output string + Error string + // Set if there was a panic within gno code. + GnoStacktrace string + // Set if this was recovered from a panic. + GoPanicStack []byte +} + +func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, content []byte) (rr runResult) { + // Eagerly load imports. + // This is executed using opts.Store, rather than the transaction store; + // it allows us to only have to load the imports once (and re-use the cached + // versions). Running the tests in separate "transactions" means that they + // don't get the parent store dirty. + if err := LoadImports(opts.TestStore, filename, content); err != nil { + // NOTE: we perform this here, so we can capture the runResult. + return runResult{Error: err.Error()} + } + + // Reset and start capturing stdout. + opts.filetestBuffer.Reset() + revert := opts.outWriter.tee(&opts.filetestBuffer) + defer revert() + + defer func() { + if r := recover(); r != nil { + rr.Output = opts.filetestBuffer.String() + rr.GoPanicStack = debug.Stack() + switch v := r.(type) { + case *gno.TypedValue: + rr.Error = v.Sprint(m) + case *gno.PreprocessError: + rr.Error = v.Unwrap().Error() + case gno.UnhandledPanicError: + rr.Error = v.Error() + rr.GnoStacktrace = m.ExceptionsStacktrace() + default: + rr.Error = fmt.Sprint(v) + rr.GnoStacktrace = m.Stacktrace().String() + } + } + }() + + // Use last element after / (works also if slash is missing). + pkgName := gno.Name(pkgPath[strings.LastIndexByte(pkgPath, '/')+1:]) + if !gno.IsRealmPath(pkgPath) { + // Simple case - pure package. + pn := gno.NewPackageNode(pkgName, pkgPath, &gno.FileSet{}) + pv := pn.NewPackage() + m.Store.SetBlockNode(pn) + m.Store.SetCachePackage(pv) + m.SetActivePackage(pv) + n := gno.MustParseFile(filename, string(content)) + m.RunFiles(n) + m.RunStatement(gno.S(gno.Call(gno.X("main")))) + } else { + // Realm case. + gno.DisableDebug() // until main call. + + // Remove filetest from name, as that can lead to the package not being + // parsed correctly when using RunMemPackage. + filename = strings.ReplaceAll(filename, "_filetest", "") + + // save package using realm crawl procedure. + memPkg := &gnovm.MemPackage{ + Name: string(pkgName), + Path: pkgPath, + Files: []*gnovm.MemFile{ + { + Name: filename, + Body: string(content), + }, + }, + } + orig, tx := m.Store, m.Store.BeginTransaction(nil, nil) + m.Store = tx + // Run decls and init functions. + m.RunMemPackage(memPkg, true) + // Clear store cache and reconstruct machine from committed info + // (mimicking on-chain behaviour). + tx.Write() + m.Store = orig + + pv2 := m.Store.GetPackage(pkgPath, false) + m.SetActivePackage(pv2) + gno.EnableDebug() + // clear store.opslog from init function(s). + m.Store.SetLogStoreOps(true) // resets. + m.RunStatement(gno.S(gno.Call(gno.X("main")))) + } + + return runResult{ + Output: opts.filetestBuffer.String(), + GnoStacktrace: m.Stacktrace().String(), + } +} + +// --------------------------------------- +// directives and directive parsing + +const ( + // These directives are used to set input variables, which should change for + // the specific filetest. They must be specified on a single line. + DirectivePkgPath = "PKGPATH" + DirectiveMaxAlloc = "MAXALLOC" + DirectiveSend = "SEND" + + // These are used to match the result of the filetest against known golden + // values. + DirectiveOutput = "Output" + DirectiveError = "Error" + DirectiveRealm = "Realm" + DirectiveEvents = "Events" + DirectivePreprocessed = "Preprocessed" + DirectiveStacktrace = "Stacktrace" +) + +// Directives contains the directives of a file. +// It may also contains directives with empty names, to indicate parts of the +// original source file (used to re-construct the filetest at the end). +type Directives []Directive + +// First returns the first directive with the corresponding name. +func (d Directives) First(name string) *Directive { + if name == "" { + return nil + } + for i := range d { + if d[i].Name == name { + return &d[i] + } + } + return nil +} + +// FirstDefault returns the [Directive.Content] of First(name); if First(name) +// returns nil, then defaultValue is returned. +func (d Directives) FirstDefault(name, defaultValue string) string { + v := d.First(name) + if v == nil { + return defaultValue + } + return v.Content +} + +// FileTest re-generates the filetest from the given directives; the inverse of ParseDirectives. +func (d Directives) FileTest() string { + var bld strings.Builder + for _, dir := range d { + switch { + case dir.Name == "": + bld.WriteString(dir.Content) + case strings.ToUpper(dir.Name) == dir.Name: // is it all uppercase? + bld.WriteString("// " + dir.Name + ": " + dir.Content + "\n") + default: + bld.WriteString("// " + dir.Name + ":\n") + cnt := strings.TrimSuffix(dir.Content, "\n") + lines := strings.Split(cnt, "\n") + for _, line := range lines { + if line == "" { + bld.WriteString("//\n") + continue + } + bld.WriteString("// ") + bld.WriteString(strings.TrimRight(line, " ")) + bld.WriteByte('\n') + } + } + } + return bld.String() +} + +// Directive represents a directive in a filetest. +// A [Directives] slice may also contain directives with empty Names: +// these compose the source file itself, and are used to re-construct the file +// when a directive is changed. +type Directive struct { + Name string + Content string +} + +// Allows either a `ALLCAPS: content` on a single line, or a `PascalCase:`, +// with content on the following lines. +var reDirectiveLine = regexp.MustCompile("^(?:([A-Z][a-z]*):|([A-Z]+): ?(.*))$") + +// ParseDirectives parses all the directives in the filetest given at source. +func ParseDirectives(source io.Reader) (Directives, error) { + sc := bufio.NewScanner(source) + parsed := make(Directives, 0, 8) + for sc.Scan() { + // Re-append trailing newline. + // Useful as we always use it anyway. + txt := sc.Text() + "\n" + if !strings.HasPrefix(txt, "//") { + if len(parsed) == 0 || parsed[len(parsed)-1].Name != "" { + parsed = append(parsed, Directive{Content: txt}) + continue + } + parsed[len(parsed)-1].Content += txt + continue + } + + comment := txt[2 : len(txt)-1] // leading double slash, trailing \n + comment = strings.TrimPrefix(comment, " ") // leading space (if any) + + // If we're already in a directive, simply append there. + if len(parsed) > 0 && parsed[len(parsed)-1].Name != "" { + parsed[len(parsed)-1].Content += comment + "\n" + continue + } + + // Find if there is a colon (indicating a possible directive). + subm := reDirectiveLine.FindStringSubmatch(comment) + switch { + case subm == nil: + // Not found; append to parsed as a line, or to the previous + // directive if it exists. + if len(parsed) == 0 { + parsed = append(parsed, Directive{Content: txt}) + continue + } + last := &parsed[len(parsed)-1] + if last.Name == "" { + last.Content += txt + } else { + last.Content += comment + "\n" + } + case subm[1] != "": // output directive, with content on newlines + parsed = append(parsed, Directive{Name: subm[1]}) + default: // subm[2] != "", all caps + parsed = append(parsed, + Directive{Name: subm[2], Content: subm[3]}, + // enforce new directive later + Directive{}, + ) + } + } + return parsed, sc.Err() +} diff --git a/gnovm/pkg/test/imports.go b/gnovm/pkg/test/imports.go new file mode 100644 index 00000000000..dabb5644cdd --- /dev/null +++ b/gnovm/pkg/test/imports.go @@ -0,0 +1,265 @@ +package test + +import ( + "encoding/json" + "errors" + "fmt" + "go/parser" + "go/token" + "io" + "math/big" + "os" + "path/filepath" + "runtime/debug" + "strconv" + "strings" + "time" + + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + teststdlibs "github.com/gnolang/gno/gnovm/tests/stdlibs" + teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" + "github.com/gnolang/gno/tm2/pkg/db/memdb" + osm "github.com/gnolang/gno/tm2/pkg/os" + "github.com/gnolang/gno/tm2/pkg/std" + "github.com/gnolang/gno/tm2/pkg/store/dbadapter" + storetypes "github.com/gnolang/gno/tm2/pkg/store/types" +) + +// NOTE: this isn't safe, should only be used for testing. +func Store( + rootDir string, + withExtern bool, + stdin io.Reader, + stdout, stderr io.Writer, +) ( + baseStore storetypes.CommitStore, + resStore gno.Store, +) { + getPackage := func(pkgPath string, store gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { + if pkgPath == "" { + panic(fmt.Sprintf("invalid zero package path in testStore().pkgGetter")) + } + + if withExtern { + // if _test package... + const testPath = "github.com/gnolang/gno/_test/" + if strings.HasPrefix(pkgPath, testPath) { + baseDir := filepath.Join(rootDir, "gnovm", "tests", "files", "extern", pkgPath[len(testPath):]) + memPkg := gno.ReadMemPackage(baseDir, pkgPath) + send := std.Coins{} + ctx := Context(pkgPath, send) + m2 := gno.NewMachineWithOptions(gno.MachineOptions{ + PkgPath: "test", + Output: stdout, + Store: store, + Context: ctx, + }) + return m2.RunMemPackage(memPkg, true) + } + } + + // gonative exceptions. + // These are values available using gonative; eventually they should all be removed. + switch pkgPath { + case "os": + pkg := gno.NewPackageNode("os", pkgPath, nil) + pkg.DefineGoNativeValue("Stdin", stdin) + pkg.DefineGoNativeValue("Stdout", stdout) + pkg.DefineGoNativeValue("Stderr", stderr) + return pkg, pkg.NewPackage() + case "fmt": + pkg := gno.NewPackageNode("fmt", pkgPath, nil) + pkg.DefineGoNativeValue("Println", func(a ...interface{}) (n int, err error) { + // NOTE: uncomment to debug long running tests + // fmt.Println(a...) + res := fmt.Sprintln(a...) + return stdout.Write([]byte(res)) + }) + pkg.DefineGoNativeValue("Printf", func(format string, a ...interface{}) (n int, err error) { + res := fmt.Sprintf(format, a...) + return stdout.Write([]byte(res)) + }) + pkg.DefineGoNativeValue("Print", func(a ...interface{}) (n int, err error) { + res := fmt.Sprint(a...) + return stdout.Write([]byte(res)) + }) + pkg.DefineGoNativeValue("Sprint", fmt.Sprint) + pkg.DefineGoNativeValue("Sprintf", fmt.Sprintf) + pkg.DefineGoNativeValue("Sprintln", fmt.Sprintln) + pkg.DefineGoNativeValue("Sscanf", fmt.Sscanf) + pkg.DefineGoNativeValue("Errorf", fmt.Errorf) + pkg.DefineGoNativeValue("Fprintln", fmt.Fprintln) + pkg.DefineGoNativeValue("Fprintf", fmt.Fprintf) + pkg.DefineGoNativeValue("Fprint", fmt.Fprint) + return pkg, pkg.NewPackage() + case "encoding/json": + pkg := gno.NewPackageNode("json", pkgPath, nil) + pkg.DefineGoNativeValue("Unmarshal", json.Unmarshal) + pkg.DefineGoNativeValue("Marshal", json.Marshal) + return pkg, pkg.NewPackage() + case "internal/os_test": + pkg := gno.NewPackageNode("os_test", pkgPath, nil) + pkg.DefineNative("Sleep", + gno.Flds( // params + "d", gno.AnyT(), // NOTE: should be time.Duration + ), + gno.Flds( // results + ), + func(m *gno.Machine) { + // For testing purposes here, nanoseconds are separately kept track. + arg0 := m.LastBlock().GetParams1().TV + d := arg0.GetInt64() + sec := d / int64(time.Second) + nano := d % int64(time.Second) + ctx := m.Context.(*teststd.TestExecContext) + ctx.Timestamp += sec + ctx.TimestampNano += nano + if ctx.TimestampNano >= int64(time.Second) { + ctx.Timestamp += 1 + ctx.TimestampNano -= int64(time.Second) + } + m.Context = ctx + }, + ) + return pkg, pkg.NewPackage() + case "math/big": + pkg := gno.NewPackageNode("big", pkgPath, nil) + pkg.DefineGoNativeValue("NewInt", big.NewInt) + return pkg, pkg.NewPackage() + } + + // Load normal stdlib. + pn, pv = loadStdlib(rootDir, pkgPath, store, stdout) + if pn != nil { + return + } + + // if examples package... + examplePath := filepath.Join(rootDir, "examples", pkgPath) + if osm.DirExists(examplePath) { + memPkg := gno.ReadMemPackage(examplePath, pkgPath) + if memPkg.IsEmpty() { + panic(fmt.Sprintf("found an empty package %q", pkgPath)) + } + + send := std.Coins{} + ctx := Context(pkgPath, send) + m2 := gno.NewMachineWithOptions(gno.MachineOptions{ + PkgPath: "test", + Output: stdout, + Store: store, + Context: ctx, + }) + pn, pv = m2.RunMemPackage(memPkg, true) + return + } + return nil, nil + } + db := memdb.NewMemDB() + baseStore = dbadapter.StoreConstructor(db, storetypes.StoreOptions{}) + // Make a new store. + resStore = gno.NewStore(nil, baseStore, baseStore) + resStore.SetPackageGetter(getPackage) + resStore.SetNativeStore(teststdlibs.NativeStore) + return +} + +func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer) (*gno.PackageNode, *gno.PackageValue) { + dirs := [...]string{ + // Normal stdlib path. + filepath.Join(rootDir, "gnovm", "stdlibs", pkgPath), + // Override path. Definitions here override the previous if duplicate. + filepath.Join(rootDir, "gnovm", "tests", "stdlibs", pkgPath), + } + files := make([]string, 0, 32) // pre-alloc 32 as a likely high number of files + for _, path := range dirs { + dl, err := os.ReadDir(path) + if err != nil { + if os.IsNotExist(err) { + continue + } + panic(fmt.Errorf("could not access dir %q: %w", path, err)) + } + + for _, f := range dl { + // NOTE: RunMemPackage has other rules; those should be mostly useful + // for on-chain packages (ie. include README and gno.mod). + if !f.IsDir() && strings.HasSuffix(f.Name(), ".gno") { + files = append(files, filepath.Join(path, f.Name())) + } + } + } + if len(files) == 0 { + return nil, nil + } + + memPkg := gno.ReadMemPackageFromList(files, pkgPath) + m2 := gno.NewMachineWithOptions(gno.MachineOptions{ + // NOTE: see also pkgs/sdk/vm/builtins.go + // Needs PkgPath != its name because TestStore.getPackage is the package + // getter for the store, which calls loadStdlib, so it would be recursively called. + PkgPath: "stdlibload", + Output: stdout, + Store: store, + }) + return m2.RunMemPackageWithOverrides(memPkg, true) +} + +type stackWrappedError struct { + err error + stack []byte +} + +func (e *stackWrappedError) Error() string { return e.err.Error() } +func (e *stackWrappedError) Unwrap() error { return e.err } +func (e *stackWrappedError) String() string { + return fmt.Sprintf("%v\nstack:\n%v", e.err, string(e.stack)) +} + +// LoadImports parses the given file and attempts to retrieve all pure packages +// from the store. This is mostly useful for "eager import loading", whereby all +// imports are pre-loaded in a permanent store, so that the tests can use +// ephemeral transaction stores. +func LoadImports(store gno.Store, filename string, content []byte) (err error) { + defer func() { + // This is slightly different from the handling below; we do not have a + // machine to work with, as this comes from an import; so we need + // "machine-less" alternatives. (like v.String instead of v.Sprint) + if r := recover(); r != nil { + switch v := r.(type) { + case *gno.TypedValue: + err = errors.New(v.String()) + case *gno.PreprocessError: + err = v.Unwrap() + case gno.UnhandledPanicError: + err = v + case error: + err = &stackWrappedError{v, debug.Stack()} + default: + err = &stackWrappedError{fmt.Errorf("%v", v), debug.Stack()} + } + } + }() + + fset := token.NewFileSet() + fl, err := parser.ParseFile(fset, filename, content, parser.ImportsOnly) + if err != nil { + return fmt.Errorf("parse failure: %w", err) + } + for _, imp := range fl.Imports { + impPath, err := strconv.Unquote(imp.Path.Value) + if err != nil { + return fmt.Errorf("%v: unexpected invalid import path: %v", fset.Position(imp.Pos()).String(), imp.Path.Value) + } + if gno.IsRealmPath(impPath) { + // Don't eagerly load realms. + // Realms persist state and can change the state of other realms in initialization. + continue + } + pkg := store.GetPackage(impPath, true) + if pkg == nil { + return fmt.Errorf("%v: unknown import path %v", fset.Position(imp.Pos()).String(), impPath) + } + } + return nil +} diff --git a/gnovm/pkg/test/test.go b/gnovm/pkg/test/test.go new file mode 100644 index 00000000000..9374db263ee --- /dev/null +++ b/gnovm/pkg/test/test.go @@ -0,0 +1,483 @@ +// Package test contains the code to parse and execute Gno tests and filetests. +package test + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "os" + "path" + "path/filepath" + "runtime/debug" + "strconv" + "strings" + "time" + + "github.com/gnolang/gno/gnovm" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + "github.com/gnolang/gno/gnovm/stdlibs" + teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" + "github.com/gnolang/gno/tm2/pkg/crypto" + "github.com/gnolang/gno/tm2/pkg/sdk" + "github.com/gnolang/gno/tm2/pkg/std" + storetypes "github.com/gnolang/gno/tm2/pkg/store/types" + "go.uber.org/multierr" +) + +const ( + // DefaultHeight is the default height used in the [Context]. + DefaultHeight = 123 + // DefaultTimestamp is the Timestamp value used by default in [Context]. + DefaultTimestamp = 1234567890 + // DefaultCaller is the result of gno.DerivePkgAddr("user1.gno"), + // used as the default caller in [Context]. + DefaultCaller crypto.Bech32Address = "g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" +) + +// Context returns a TestExecContext. Usable for test purpose only. +// The returned context has a mock banker, params and event logger. It will give +// the pkgAddr the coins in `send` by default, and only that. +// The Height and Timestamp parameters are set to the [DefaultHeight] and +// [DefaultTimestamp]. +func Context(pkgPath string, send std.Coins) *teststd.TestExecContext { + // FIXME: create a better package to manage this, with custom constructors + pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called. + + banker := &teststd.TestBanker{ + CoinTable: map[crypto.Bech32Address]std.Coins{ + pkgAddr.Bech32(): send, + }, + } + ctx := stdlibs.ExecContext{ + ChainID: "dev", + Height: DefaultHeight, + Timestamp: DefaultTimestamp, + OrigCaller: DefaultCaller, + OrigPkgAddr: pkgAddr.Bech32(), + OrigSend: send, + OrigSendSpent: new(std.Coins), + Banker: banker, + Params: newTestParams(), + EventLogger: sdk.NewEventLogger(), + } + return &teststd.TestExecContext{ + ExecContext: ctx, + RealmFrames: make(map[*gno.Frame]teststd.RealmOverride), + } +} + +// Machine is a minimal machine, set up with just the Store, Output and Context. +func Machine(testStore gno.Store, output io.Writer, pkgPath string) *gno.Machine { + return gno.NewMachineWithOptions(gno.MachineOptions{ + Store: testStore, + Output: output, + Context: Context(pkgPath, nil), + }) +} + +// ---------------------------------------- +// testParams + +type testParams struct{} + +func newTestParams() *testParams { + return &testParams{} +} + +func (tp *testParams) SetBool(key string, val bool) { /* noop */ } +func (tp *testParams) SetBytes(key string, val []byte) { /* noop */ } +func (tp *testParams) SetInt64(key string, val int64) { /* noop */ } +func (tp *testParams) SetUint64(key string, val uint64) { /* noop */ } +func (tp *testParams) SetString(key string, val string) { /* noop */ } + +// ---------------------------------------- +// main test function + +// TestOptions is a list of options that must be passed to [Test]. +type TestOptions struct { + // BaseStore / TestStore to use for the tests. + BaseStore storetypes.CommitStore + TestStore gno.Store + // Gno root dir. + RootDir string + // Used for printing program output, during verbose logging. + Output io.Writer + // Used for os.Stderr, and for printing errors. + Error io.Writer + + // Not set by NewTestOptions: + + // Flag to filter tests to run. + RunFlag string + // Whether to update filetest directives. + Sync bool + // Uses Error to print when starting a test, and prints test output directly, + // unbuffered. + Verbose bool + // Uses Error to print runtime metrics for tests. + Metrics bool + // Uses Error to print the events emitted. + Events bool + + filetestBuffer bytes.Buffer + outWriter proxyWriter +} + +// WriterForStore is the writer that should be passed to [Store], so that +// [Test] is then able to swap it when needed. +func (opts *TestOptions) WriterForStore() io.Writer { + return &opts.outWriter +} + +// NewTestOptions sets up TestOptions, filling out all "required" parameters. +func NewTestOptions(rootDir string, stdin io.Reader, stdout, stderr io.Writer) *TestOptions { + opts := &TestOptions{ + RootDir: rootDir, + Output: stdout, + Error: stderr, + } + opts.BaseStore, opts.TestStore = Store( + rootDir, false, + stdin, opts.WriterForStore(), stderr, + ) + return opts +} + +// proxyWriter is a simple wrapper around a io.Writer, it exists so that the +// underlying writer can be swapped with another when necessary. +type proxyWriter struct { + w io.Writer +} + +func (p *proxyWriter) Write(b []byte) (int, error) { + return p.w.Write(b) +} + +// tee temporarily appends the writer w to an underlying MultiWriter, which +// should then be reverted using revert(). +func (p *proxyWriter) tee(w io.Writer) (revert func()) { + save := p.w + if save == io.Discard { + p.w = w + } else { + p.w = io.MultiWriter(save, w) + } + return func() { + p.w = save + } +} + +// Test runs tests on the specified memPkg. +// fsDir is the directory on filesystem of package; it's used in case opts.Sync +// is enabled, and points to the directory where the files are contained if they +// are to be updated. +// opts is a required set of options, which is often shared among different +// tests; you can use [NewTestOptions] for a common base configuration. +func Test(memPkg *gnovm.MemPackage, fsDir string, opts *TestOptions) error { + opts.outWriter.w = opts.Output + + var errs error + + // Stands for "test", "integration test", and "filetest". + // "integration test" are the test files with `package xxx_test` (they are + // not necessarily integration tests, it's just for our internal reference.) + tset, itset, itfiles, ftfiles := parseMemPackageTests(opts.TestStore, memPkg) + + // Testing with *_test.gno + if len(tset.Files)+len(itset.Files) > 0 { + // Create a common cw/gs for both the `pkg` tests as well as the `pkg_test` + // tests. This allows us to "export" symbols from the pkg tests and + // import them from the `pkg_test` tests. + cw := opts.BaseStore.CacheWrap() + gs := opts.TestStore.BeginTransaction(cw, cw) + + // Run test files in pkg. + if len(tset.Files) > 0 { + err := opts.runTestFiles(memPkg, tset, cw, gs) + if err != nil { + errs = multierr.Append(errs, err) + } + } + + // Test xxx_test pkg. + if len(itset.Files) > 0 { + itPkg := &gnovm.MemPackage{ + Name: memPkg.Name + "_test", + Path: memPkg.Path + "_test", + Files: itfiles, + } + + err := opts.runTestFiles(itPkg, itset, cw, gs) + if err != nil { + errs = multierr.Append(errs, err) + } + } + } + + // Testing with *_filetest.gno. + if len(ftfiles) > 0 { + filter := splitRegexp(opts.RunFlag) + for _, testFile := range ftfiles { + testFileName := testFile.Name + testFilePath := filepath.Join(fsDir, testFileName) + testName := "file/" + testFileName + if !shouldRun(filter, testName) { + continue + } + + startedAt := time.Now() + if opts.Verbose { + fmt.Fprintf(opts.Error, "=== RUN %s\n", testName) + } + + changed, err := opts.runFiletest(testFileName, []byte(testFile.Body)) + if changed != "" { + // Note: changed always == "" if opts.Sync == false. + err = os.WriteFile(testFilePath, []byte(changed), 0o644) + if err != nil { + panic(fmt.Errorf("could not fix golden file: %w", err)) + } + } + + duration := time.Since(startedAt) + dstr := fmtDuration(duration) + if err != nil { + fmt.Fprintf(opts.Error, "--- FAIL: %s (%s)\n", testName, dstr) + fmt.Fprintln(opts.Error, err.Error()) + errs = multierr.Append(errs, fmt.Errorf("%s failed", testName)) + } else if opts.Verbose { + fmt.Fprintf(opts.Error, "--- PASS: %s (%s)\n", testName, dstr) + } + + // XXX: add per-test metrics + } + } + + return errs +} + +func (opts *TestOptions) runTestFiles( + memPkg *gnovm.MemPackage, + files *gno.FileSet, + cw storetypes.Store, gs gno.TransactionStore, +) (errs error) { + var m *gno.Machine + defer func() { + if r := recover(); r != nil { + if st := m.ExceptionsStacktrace(); st != "" { + errs = multierr.Append(errors.New(st), errs) + } + errs = multierr.Append( + fmt.Errorf("panic: %v\ngo stacktrace:\n%v\ngno machine: %v\ngno stacktrace:\n%v", + r, string(debug.Stack()), m.String(), m.Stacktrace()), + errs, + ) + } + }() + + tests := loadTestFuncs(memPkg.Name, files) + + var alloc *gno.Allocator + if opts.Metrics { + alloc = gno.NewAllocator(math.MaxInt64) + } + + // Check if we already have the package - it may have been eagerly + // loaded. + m = Machine(gs, opts.WriterForStore(), memPkg.Path) + m.Alloc = alloc + if opts.TestStore.GetMemPackage(memPkg.Path) == nil { + m.RunMemPackage(memPkg, true) + } else { + m.SetActivePackage(gs.GetPackage(memPkg.Path, false)) + } + pv := m.Package + + m.RunFiles(files.Files...) + + for _, tf := range tests { + // TODO(morgan): we could theoretically use wrapping on the baseStore + // and gno store to achieve per-test isolation. However, that requires + // some deeper changes, as ideally we'd: + // - Run the MemPackage independently (so it can also be run as a + // consequence of an import) + // - Run the test files before this for loop (but persist it to store; + // RunFiles doesn't do that currently) + // - Wrap here. + m = Machine(gs, opts.Output, memPkg.Path) + m.Alloc = alloc + m.SetActivePackage(pv) + + testingpv := m.Store.GetPackage("testing", false) + testingtv := gno.TypedValue{T: &gno.PackageType{}, V: testingpv} + testingcx := &gno.ConstExpr{TypedValue: testingtv} + + eval := m.Eval(gno.Call( + gno.Sel(testingcx, "RunTest"), // Call testing.RunTest + gno.Str(opts.RunFlag), // run flag + gno.Nx(strconv.FormatBool(opts.Verbose)), // is verbose? + &gno.CompositeLitExpr{ // Third param, the testing.InternalTest + Type: gno.Sel(testingcx, "InternalTest"), + Elts: gno.KeyValueExprs{ + {Key: gno.X("Name"), Value: gno.Str(tf.Name)}, + {Key: gno.X("F"), Value: gno.Nx(tf.Name)}, + }, + }, + )) + + if opts.Events { + events := m.Context.(*teststd.TestExecContext).EventLogger.Events() + if events != nil { + res, err := json.Marshal(events) + if err != nil { + panic(err) + } + fmt.Fprintf(opts.Error, "EVENTS: %s\n", string(res)) + } + } + + ret := eval[0].GetString() + if ret == "" { + err := fmt.Errorf("failed to execute unit test: %q", tf.Name) + errs = multierr.Append(errs, err) + fmt.Fprintf(opts.Error, "--- FAIL: %s [internal gno testing error]", tf.Name) + continue + } + + // TODO: replace with amino or send native type? + var rep report + err := json.Unmarshal([]byte(ret), &rep) + if err != nil { + errs = multierr.Append(errs, err) + fmt.Fprintf(opts.Error, "--- FAIL: %s [internal gno testing error]", tf.Name) + continue + } + + if rep.Failed { + err := fmt.Errorf("failed: %q", tf.Name) + errs = multierr.Append(errs, err) + } + + if opts.Metrics { + // XXX: store changes + // XXX: max mem consumption + allocsVal := "n/a" + if m.Alloc != nil { + maxAllocs, allocs := m.Alloc.Status() + allocsVal = fmt.Sprintf("%s(%.2f%%)", + prettySize(allocs), + float64(allocs)/float64(maxAllocs)*100, + ) + } + fmt.Fprintf(opts.Error, "--- runtime: cycle=%s allocs=%s\n", + prettySize(m.Cycles), + allocsVal, + ) + } + } + + return errs +} + +// report is a mirror of Gno's stdlibs/testing.Report. +type report struct { + Failed bool + Skipped bool +} + +type testFunc struct { + Package string + Name string +} + +func loadTestFuncs(pkgName string, tfiles *gno.FileSet) (rt []testFunc) { + for _, tf := range tfiles.Files { + for _, d := range tf.Decls { + if fd, ok := d.(*gno.FuncDecl); ok { + fname := string(fd.Name) + if strings.HasPrefix(fname, "Test") { + tf := testFunc{ + Package: pkgName, + Name: fname, + } + rt = append(rt, tf) + } + } + } + } + return +} + +// parseMemPackageTests parses test files (skipping filetests) in the memPkg. +func parseMemPackageTests(store gno.Store, memPkg *gnovm.MemPackage) (tset, itset *gno.FileSet, itfiles, ftfiles []*gnovm.MemFile) { + tset = &gno.FileSet{} + itset = &gno.FileSet{} + var errs error + for _, mfile := range memPkg.Files { + if !strings.HasSuffix(mfile.Name, ".gno") { + continue // skip this file. + } + + if err := LoadImports(store, path.Join(memPkg.Path, mfile.Name), []byte(mfile.Body)); err != nil { + errs = multierr.Append(errs, err) + } + + n, err := gno.ParseFile(mfile.Name, mfile.Body) + if err != nil { + errs = multierr.Append(errs, err) + continue + } + if n == nil { + panic("should not happen") + } + switch { + case strings.HasSuffix(mfile.Name, "_filetest.gno"): + ftfiles = append(ftfiles, mfile) + case strings.HasSuffix(mfile.Name, "_test.gno") && memPkg.Name == string(n.PkgName): + tset.AddFiles(n) + case strings.HasSuffix(mfile.Name, "_test.gno") && memPkg.Name+"_test" == string(n.PkgName): + itset.AddFiles(n) + itfiles = append(itfiles, mfile) + case memPkg.Name == string(n.PkgName): + // normal package file + default: + panic(fmt.Sprintf( + "expected package name [%s] or [%s_test] but got [%s] file [%s]", + memPkg.Name, memPkg.Name, n.PkgName, mfile)) + } + } + if errs != nil { + panic(errs) + } + return +} + +func shouldRun(filter filterMatch, path string) bool { + if filter == nil { + return true + } + elem := strings.Split(path, "/") + ok, _ := filter.matches(elem, matchString) + return ok +} + +// Adapted from https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format/ +func prettySize(nb int64) string { + const unit = 1000 + if nb < unit { + return fmt.Sprintf("%d", nb) + } + div, exp := int64(unit), 0 + for n := nb / unit; n >= unit; n /= unit { + div *= unit + exp++ + } + return fmt.Sprintf("%.1f%c", float64(nb)/float64(div), "kMGTPE"[exp]) +} + +func fmtDuration(d time.Duration) string { + return fmt.Sprintf("%.2fs", d.Seconds()) +} diff --git a/gnovm/cmd/gno/util_match.go b/gnovm/pkg/test/util_match.go similarity index 99% rename from gnovm/cmd/gno/util_match.go rename to gnovm/pkg/test/util_match.go index 34181f61254..a3fec22f389 100644 --- a/gnovm/cmd/gno/util_match.go +++ b/gnovm/pkg/test/util_match.go @@ -1,4 +1,4 @@ -package main +package test // Most of the code in this file is extracted from golang's src/testing/match.go. // diff --git a/gnovm/stdlibs/io/example_test.gno b/gnovm/stdlibs/io/example_test.gno index c781fb9166e..54a9e74f55a 100644 --- a/gnovm/stdlibs/io/example_test.gno +++ b/gnovm/stdlibs/io/example_test.gno @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "log" "os" "strings" ) @@ -17,7 +16,7 @@ func ExampleCopy() { r := strings.NewReader("some io.Reader stream to be read\n") if _, err := io.Copy(os.Stdout, r); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -31,12 +30,12 @@ func ExampleCopyBuffer() { // buf is used here... if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil { - log.Fatal(err) + panic(err) } // ... reused here also. No need to allocate an extra buffer. if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -48,7 +47,7 @@ func ExampleCopyN() { r := strings.NewReader("some io.Reader stream to be read") if _, err := io.CopyN(os.Stdout, r, 4); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -60,7 +59,7 @@ func ExampleReadAtLeast() { buf := make([]byte, 14) if _, err := io.ReadAtLeast(r, buf, 4); err != nil { - log.Fatal(err) + panic(err) } fmt.Printf("%s\n", buf) @@ -87,7 +86,7 @@ func ExampleReadFull() { buf := make([]byte, 4) if _, err := io.ReadFull(r, buf); err != nil { - log.Fatal(err) + panic(err) } fmt.Printf("%s\n", buf) @@ -104,7 +103,7 @@ func ExampleReadFull() { func ExampleWriteString() { if _, err := io.WriteString(os.Stdout, "Hello World"); err != nil { - log.Fatal(err) + panic(err) } // Output: Hello World @@ -115,7 +114,7 @@ func ExampleLimitReader() { lr := io.LimitReader(r, 4) if _, err := io.Copy(os.Stdout, lr); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -129,7 +128,7 @@ func ExampleMultiReader() { r := io.MultiReader(r1, r2, r3) if _, err := io.Copy(os.Stdout, r); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -153,7 +152,7 @@ func ExampleSectionReader() { s := io.NewSectionReader(r, 5, 17) if _, err := io.Copy(os.Stdout, s); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -166,7 +165,7 @@ func ExampleSectionReader_ReadAt() { buf := make([]byte, 6) if _, err := s.ReadAt(buf, 10); err != nil { - log.Fatal(err) + panic(err) } fmt.Printf("%s\n", buf) @@ -180,11 +179,11 @@ func ExampleSectionReader_Seek() { s := io.NewSectionReader(r, 5, 17) if _, err := s.Seek(10, io.SeekStart); err != nil { - log.Fatal(err) + panic(err) } if _, err := io.Copy(os.Stdout, s); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -196,12 +195,12 @@ func ExampleSeeker_Seek() { r.Seek(5, io.SeekStart) // move to the 5th char from the start if _, err := io.Copy(os.Stdout, r); err != nil { - log.Fatal(err) + panic(err) } r.Seek(-5, io.SeekEnd) if _, err := io.Copy(os.Stdout, r); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -216,7 +215,7 @@ func ExampleMultiWriter() { w := io.MultiWriter(&buf1, &buf2) if _, err := io.Copy(w, r); err != nil { - log.Fatal(err) + panic(err) } fmt.Print(buf1.String()) @@ -237,7 +236,7 @@ func ExamplePipe() { }() if _, err := io.Copy(os.Stdout, r); err != nil { - log.Fatal(err) + panic(err) } // Output: @@ -250,7 +249,7 @@ func ExampleReadAll() { b, err := io.ReadAll(r) if err != nil { - log.Fatal(err) + panic(err) } fmt.Printf("%s", b) diff --git a/gnovm/stdlibs/io/multi_test.gno b/gnovm/stdlibs/io/multi_test.gno index 8932ace2e59..f39895ea776 100644 --- a/gnovm/stdlibs/io/multi_test.gno +++ b/gnovm/stdlibs/io/multi_test.gno @@ -6,7 +6,7 @@ package io import ( "bytes" - "crypto/sha1" + "crypto/sha256" "fmt" "strings" "testing" @@ -119,8 +119,8 @@ func testMultiWriter(t *testing.T, sink interface { Stringer }, ) { - sha1 := sha1.New() - mw := MultiWriter(sha1, sink) + var buf bytes.Buffer + mw := MultiWriter(&buf, sink) sourceString := "My input text." source := strings.NewReader(sourceString) @@ -134,9 +134,9 @@ func testMultiWriter(t *testing.T, sink interface { t.Errorf("unexpected error: %v", err) } - sha1hex := fmt.Sprintf("%x", sha1.Sum(nil)) - if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" { - t.Error("incorrect sha1 value") + sha1hex := fmt.Sprintf("%x", sha256.Sum256(buf.Bytes())) + if sha1hex != "d3e9e78d2a7e9c4756a4e8e57db6a57ccfd84c6d656d66b9d2bd2620b4ab81b8" { + t.Error("incorrect sha256 value") } if sink.String() != sourceString { diff --git a/gnovm/stdlibs/std/context.go b/gnovm/stdlibs/std/context.go index a0dafe5dc44..01e763ab82e 100644 --- a/gnovm/stdlibs/std/context.go +++ b/gnovm/stdlibs/std/context.go @@ -12,7 +12,6 @@ type ExecContext struct { Height int64 Timestamp int64 // seconds TimestampNano int64 // nanoseconds, only used for testing. - Msg sdk.Msg OrigCaller crypto.Bech32Address OrigPkgAddr crypto.Bech32Address OrigSend std.Coins diff --git a/gnovm/stdlibs/strconv/example_test.gno b/gnovm/stdlibs/strconv/example_test.gno index 428fde4e660..d3ef2cc4244 100644 --- a/gnovm/stdlibs/strconv/example_test.gno +++ b/gnovm/stdlibs/strconv/example_test.gno @@ -6,7 +6,6 @@ package strconv_test import ( "fmt" - "log" "strconv" ) @@ -409,7 +408,7 @@ func ExampleUnquote() { func ExampleUnquoteChar() { v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"') if err != nil { - log.Fatal(err) + panic(err) } fmt.Println("value:", string(v)) diff --git a/gnovm/stdlibs/testing/match.gno b/gnovm/stdlibs/testing/match.gno index 3b22602890d..8b099f37624 100644 --- a/gnovm/stdlibs/testing/match.gno +++ b/gnovm/stdlibs/testing/match.gno @@ -16,11 +16,11 @@ import ( type filterMatch interface { // matches checks the name against the receiver's pattern strings using the // given match function. - matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) + matches(name []string) (ok, partial bool) // verify checks that the receiver's pattern strings are valid filters by // calling the given match function. - verify(name string, matchString func(pat, str string) (bool, error)) error + verify(name string) error } // simpleMatch matches a test name if all of the pattern strings match in @@ -30,43 +30,43 @@ type simpleMatch []string // alternationMatch matches a test name if one of the alternations match. type alternationMatch []filterMatch -func (m simpleMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) { +func (m simpleMatch) matches(name []string) (ok, partial bool) { for i, s := range name { if i >= len(m) { break } - if ok, _ := matchString(m[i], s); !ok { + if ok, _ := regexp.MatchString(m[i], s); !ok { return false, false } } return true, len(name) < len(m) } -func (m simpleMatch) verify(name string, matchString func(pat, str string) (bool, error)) error { +func (m simpleMatch) verify(name string) error { for i, s := range m { m[i] = rewrite(s) } // Verify filters before doing any processing. for i, s := range m { - if _, err := matchString(s, "non-empty"); err != nil { + if _, err := regexp.MatchString(s, "non-empty"); err != nil { return fmt.Errorf("element %d of %s (%q): %s", i, name, s, err) } } return nil } -func (m alternationMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) { +func (m alternationMatch) matches(name []string) (ok, partial bool) { for _, m := range m { - if ok, partial = m.matches(name, matchString); ok { + if ok, partial = m.matches(name); ok { return ok, partial } } return false, false } -func (m alternationMatch) verify(name string, matchString func(pat, str string) (bool, error)) error { +func (m alternationMatch) verify(name string) error { for i, m := range m { - if err := m.verify(name, matchString); err != nil { + if err := m.verify(name); err != nil { return fmt.Errorf("alternation %d of %s", i, err) } } @@ -164,20 +164,3 @@ func isSpace(r rune) bool { } return false } - -var ( - matchPat string - matchRe *regexp.Regexp -) - -// based on testing/internal/testdeps.TestDeps.MatchString. -func matchString(pat, str string) (result bool, err error) { - if matchRe == nil || matchPat != pat { - matchPat = pat - matchRe, err = regexp.Compile(matchPat) - if err != nil { - return - } - } - return matchRe.MatchString(str), nil -} diff --git a/gnovm/stdlibs/testing/testing.gno b/gnovm/stdlibs/testing/testing.gno index 6e55c5cc283..fdafd9652ba 100644 --- a/gnovm/stdlibs/testing/testing.gno +++ b/gnovm/stdlibs/testing/testing.gno @@ -280,7 +280,7 @@ func (t *T) shouldRun(name string) bool { } elem := strings.Split(name, "/") - ok, partial := t.runFilter.matches(elem, matchString) + ok, partial := t.runFilter.matches(elem) _ = partial // we don't care right now return ok } diff --git a/gnovm/tests/README.md b/gnovm/tests/README.md index 378d5d9dc1b..d35c6590e2f 100644 --- a/gnovm/tests/README.md +++ b/gnovm/tests/README.md @@ -1 +1,35 @@ -All the files in the ./files directory are meant to be those derived/borrowed from Yaegi, Apache2.0. +# tests + +This directory contains integration tests for the GnoVM. This file aims to provide a brief overview. + +GnoVM tests and filetests run in a special context relating to its imports. +You can see the additional Gonative functions in [gnovm/pkg/test/imports.go](../pkg/test/imports.go). +You can see additional standard libraries and standard library functions +available in testing in [gnovm/tests/stdlibs](./stdlibs). + +## `files`: GnoVM filetests + +The most important directory is `files`, which contains filetests for the Gno +project. These are executed by the `TestFiles` test in the `gnovm/pkg/gnolang` +directory. + +The `files/extern` directory contains several packages used to test the import +system. The packages here are imported with the prefix +`github.com/gnolang/gno/_test/`, exclusively within these filetests. + +Tests with the `_long` suffix are skipped when the `-short` flag is passed. + +These tests are largely derived from Yaegi, licensed under Apache 2.0. + +## `stdlibs`: testing standard libraries + +These contain standard libraries which are only available in testing, and +extensions of them, like `std.TestSkipHeights`. + +## other directories + +- `backup` has been here since forever; and somebody should come around and delete it at some point. +- `challenges` contains code that supposedly doesn't work, but should. +- `integ` contains some files for integration tests which likely should have + been in some `testdata` directory to begin with. You guessed it, + they're here until someone bothers to move them out. diff --git a/gnovm/tests/file.go b/gnovm/tests/file.go deleted file mode 100644 index 98dbab6ac0e..00000000000 --- a/gnovm/tests/file.go +++ /dev/null @@ -1,713 +0,0 @@ -package tests - -import ( - "bytes" - "encoding/json" - "fmt" - "go/ast" - "go/parser" - "go/token" - "io" - "os" - "regexp" - rtdb "runtime/debug" - "strconv" - "strings" - - "github.com/gnolang/gno/gno.land/pkg/gnoland/ugnot" - "github.com/gnolang/gno/gnovm" - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/stdlibs" - teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" - "github.com/gnolang/gno/tm2/pkg/crypto" - osm "github.com/gnolang/gno/tm2/pkg/os" - "github.com/gnolang/gno/tm2/pkg/sdk" - "github.com/gnolang/gno/tm2/pkg/std" - "github.com/pmezard/go-difflib/difflib" -) - -type loggerFunc func(args ...interface{}) - -func TestMachine(store gno.Store, stdout io.Writer, pkgPath string) *gno.Machine { - // default values - var ( - send std.Coins - maxAlloc int64 - ) - - return testMachineCustom(store, pkgPath, stdout, maxAlloc, send) -} - -func testMachineCustom(store gno.Store, pkgPath string, stdout io.Writer, maxAlloc int64, send std.Coins) *gno.Machine { - ctx := TestContext(pkgPath, send) - m := gno.NewMachineWithOptions(gno.MachineOptions{ - PkgPath: "", // set later. - Output: stdout, - Store: store, - Context: ctx, - MaxAllocBytes: maxAlloc, - }) - return m -} - -// TestContext returns a TestExecContext. Usable for test purpose only. -func TestContext(pkgPath string, send std.Coins) *teststd.TestExecContext { - // FIXME: create a better package to manage this, with custom constructors - pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called. - caller := gno.DerivePkgAddr("user1.gno") - - pkgCoins := std.MustParseCoins(ugnot.ValueString(200_000_000)).Add(send) // >= send. - banker := newTestBanker(pkgAddr.Bech32(), pkgCoins) - params := newTestParams() - ctx := stdlibs.ExecContext{ - ChainID: "dev", - Height: 123, - Timestamp: 1234567890, - Msg: nil, - OrigCaller: caller.Bech32(), - OrigPkgAddr: pkgAddr.Bech32(), - OrigSend: send, - OrigSendSpent: new(std.Coins), - Banker: banker, - Params: params, - EventLogger: sdk.NewEventLogger(), - } - return &teststd.TestExecContext{ - ExecContext: ctx, - RealmFrames: make(map[*gno.Frame]teststd.RealmOverride), - } -} - -// CleanupMachine can be called during two tests while reusing the same Machine instance. -func CleanupMachine(m *gno.Machine) { - prevCtx := m.Context.(*teststd.TestExecContext) - prevSend := prevCtx.OrigSend - - newCtx := TestContext("", prevCtx.OrigSend) - pkgCoins := std.MustParseCoins(ugnot.ValueString(200_000_000)).Add(prevSend) // >= send. - banker := newTestBanker(prevCtx.OrigPkgAddr, pkgCoins) - newCtx.OrigPkgAddr = prevCtx.OrigPkgAddr - newCtx.Banker = banker - m.Context = newCtx -} - -type runFileTestOptions struct { - nativeLibs bool - logger loggerFunc - syncWanted bool -} - -// RunFileTestOptions specify changing options in [RunFileTest], deviating -// from the zero value. -type RunFileTestOption func(*runFileTestOptions) - -// WithNativeLibs enables using go native libraries (ie, [ImportModeNativePreferred]) -// instead of using stdlibs/*. -func WithNativeLibs() RunFileTestOption { - return func(r *runFileTestOptions) { r.nativeLibs = true } -} - -// WithLoggerFunc sets a logging function for [RunFileTest]. -func WithLoggerFunc(f func(args ...interface{})) RunFileTestOption { - return func(r *runFileTestOptions) { r.logger = f } -} - -// WithSyncWanted sets the syncWanted flag to true. -// It rewrites tests files so that the values of Output: and of Realm: -// comments match the actual output or realm state after the test. -func WithSyncWanted(v bool) RunFileTestOption { - return func(r *runFileTestOptions) { r.syncWanted = v } -} - -// RunFileTest executes the filetest at the given path, using rootDir as -// the directory where to find the "stdlibs" directory. -func RunFileTest(rootDir string, path string, opts ...RunFileTestOption) error { - var f runFileTestOptions - for _, opt := range opts { - opt(&f) - } - - directives, pkgPath, resWanted, errWanted, rops, eventsWanted, stacktraceWanted, maxAlloc, send, preWanted := wantedFromComment(path) - if pkgPath == "" { - pkgPath = "main" - } - pkgName := DefaultPkgName(pkgPath) - stdin := new(bytes.Buffer) - stdout := new(bytes.Buffer) - stderr := new(bytes.Buffer) - mode := ImportModeStdlibsPreferred - if f.nativeLibs { - mode = ImportModeNativePreferred - } - store := TestStore(rootDir, "./files", stdin, stdout, stderr, mode) - store.SetLogStoreOps(true) - m := testMachineCustom(store, pkgPath, stdout, maxAlloc, send) - checkMachineIsEmpty := true - - // TODO support stdlib groups, but make testing safe; - // e.g. not be able to make network connections. - // interp.New(interp.Options{GoPath: goPath, Stdout: &stdout, Stderr: &stderr}) - // m.Use(interp.Symbols) - // m.Use(stdlib.Symbols) - // m.Use(unsafe.Symbols) - bz, err := os.ReadFile(path) - if err != nil { - return err - } - { // Validate result, errors, etc. - var pnc interface{} - func() { - defer func() { - if r := recover(); r != nil { - // print output. - fmt.Printf("OUTPUT:\n%s\n", stdout.String()) - pnc = r - err := strings.TrimSpace(fmt.Sprintf("%v", pnc)) - // print stack if unexpected error. - if errWanted == "" || - !strings.Contains(err, errWanted) { - fmt.Printf("ERROR:\n%s\n", err) - // error didn't match: print stack - // NOTE: will fail testcase later. - rtdb.PrintStack() - } - } - }() - if f.logger != nil { - f.logger("========================================") - f.logger("RUN FILES & INIT") - f.logger("========================================") - } - if !gno.IsRealmPath(pkgPath) { - // simple case. - pn := gno.NewPackageNode(pkgName, pkgPath, &gno.FileSet{}) - pv := pn.NewPackage() - store.SetBlockNode(pn) - store.SetCachePackage(pv) - m.SetActivePackage(pv) - n := gno.MustParseFile(path, string(bz)) // "main.gno", string(bz)) - m.RunFiles(n) - if f.logger != nil { - f.logger("========================================") - f.logger("RUN MAIN") - f.logger("========================================") - } - m.RunMain() - if f.logger != nil { - f.logger("========================================") - f.logger("RUN MAIN END") - f.logger("========================================") - } - } else { - // realm case. - store.SetStrictGo2GnoMapping(true) // in gno.land, natives must be registered. - gno.DisableDebug() // until main call. - // save package using realm crawl procedure. - memPkg := &gnovm.MemPackage{ - Name: string(pkgName), - Path: pkgPath, - Files: []*gnovm.MemFile{ - { - Name: "main.gno", // dontcare - Body: string(bz), - }, - }, - } - // run decls and init functions. - m.RunMemPackage(memPkg, true) - // reconstruct machine and clear store cache. - // whether package is realm or not, since non-realm - // may call realm packages too. - if f.logger != nil { - f.logger("========================================") - f.logger("CLEAR STORE CACHE") - f.logger("========================================") - } - store.ClearCache() - /* - m = gno.NewMachineWithOptions(gno.MachineOptions{ - PkgPath: "", - Output: stdout, - Store: store, - Context: ctx, - MaxAllocBytes: maxAlloc, - }) - */ - if f.logger != nil { - store.Print() - f.logger("========================================") - f.logger("PREPROCESS ALL FILES") - f.logger("========================================") - } - m.PreprocessAllFilesAndSaveBlockNodes() - if f.logger != nil { - f.logger("========================================") - f.logger("RUN MAIN") - f.logger("========================================") - store.Print() - } - pv2 := store.GetPackage(pkgPath, false) - m.SetActivePackage(pv2) - gno.EnableDebug() - if rops != "" { - // clear store.opslog from init function(s), - // and PreprocessAllFilesAndSaveBlockNodes(). - store.SetLogStoreOps(true) // resets. - } - m.RunMain() - if f.logger != nil { - f.logger("========================================") - f.logger("RUN MAIN END") - f.logger("========================================") - } - } - }() - - for _, directive := range directives { - switch directive { - case "Error": - // errWanted given - if errWanted != "" { - if pnc == nil { - panic(fmt.Sprintf("fail on %s: got nil error, want: %q", path, errWanted)) - } - - errstr := "" - switch v := pnc.(type) { - case *gno.TypedValue: - errstr = v.Sprint(m) - case *gno.PreprocessError: - errstr = v.Unwrap().Error() - case gno.UnhandledPanicError: - errstr = v.Error() - default: - errstr = strings.TrimSpace(fmt.Sprintf("%v", pnc)) - } - - parts := strings.SplitN(errstr, ":\n--- preprocess stack ---", 2) - if len(parts) == 2 { - fmt.Println(parts[0]) - errstr = parts[0] - } - if errstr != errWanted { - if f.syncWanted { - // write error to file - replaceWantedInPlace(path, "Error", errstr) - } else { - panic(fmt.Sprintf("fail on %s: got %q, want: %q", path, errstr, errWanted)) - } - } - - // NOTE: ignores any gno.GetDebugErrors(). - gno.ClearDebugErrors() - checkMachineIsEmpty = false // nothing more to do. - } else { - // record errors when errWanted is empty and pnc not nil - if pnc != nil { - errstr := "" - if tv, ok := pnc.(*gno.TypedValue); ok { - errstr = tv.Sprint(m) - } else { - errstr = strings.TrimSpace(fmt.Sprintf("%v", pnc)) - } - parts := strings.SplitN(errstr, ":\n--- preprocess stack ---", 2) - if len(parts) == 2 { - fmt.Println(parts[0]) - errstr = parts[0] - } - // check tip line, write to file - ctl := errstr + - "\n*** CHECK THE ERR MESSAGES ABOVE, MAKE SURE IT'S WHAT YOU EXPECTED, " + - "DELETE THIS LINE AND RUN TEST AGAIN ***" - // write error to file - replaceWantedInPlace(path, "Error", ctl) - panic(fmt.Sprintf("fail on %s: err recorded, check the message and run test again", path)) - } - // check gno debug errors when errWanted is empty, pnc is nil - if gno.HasDebugErrors() { - panic(fmt.Sprintf("fail on %s: got unexpected debug error(s): %v", path, gno.GetDebugErrors())) - } - // pnc is nil, errWanted empty, no gno debug errors - checkMachineIsEmpty = false - } - case "Output": - // panic if got unexpected error - if pnc != nil { - if tv, ok := pnc.(*gno.TypedValue); ok { - panic(fmt.Sprintf("fail on %s: got unexpected error: %s", path, tv.Sprint(m))) - } else { // happens on 'unknown import path ...' - panic(fmt.Sprintf("fail on %s: got unexpected error: %v", path, pnc)) - } - } - // check result - res := strings.TrimSpace(stdout.String()) - res = trimTrailingSpaces(res) - if res != resWanted { - if f.syncWanted { - // write output to file. - replaceWantedInPlace(path, "Output", res) - } else { - // panic so tests immediately fail (for now). - if resWanted == "" { - panic(fmt.Sprintf("fail on %s: got unexpected output: %s", path, res)) - } else { - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(resWanted), - B: difflib.SplitLines(res), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) - } - } - } - case "Events": - // panic if got unexpected error - - if pnc != nil { - if tv, ok := pnc.(*gno.TypedValue); ok { - panic(fmt.Sprintf("fail on %s: got unexpected error: %s", path, tv.Sprint(m))) - } else { // happens on 'unknown import path ...' - panic(fmt.Sprintf("fail on %s: got unexpected error: %v", path, pnc)) - } - } - // check result - events := m.Context.(*teststd.TestExecContext).EventLogger.Events() - evtjson, err := json.MarshalIndent(events, "", " ") - if err != nil { - panic(err) - } - evtstr := trimTrailingSpaces(string(evtjson)) - if evtstr != eventsWanted { - if f.syncWanted { - // write output to file. - replaceWantedInPlace(path, "Events", evtstr) - } else { - // panic so tests immediately fail (for now). - if eventsWanted == "" { - panic(fmt.Sprintf("fail on %s: got unexpected events: %s", path, evtstr)) - } else { - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(eventsWanted), - B: difflib.SplitLines(evtstr), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) - } - } - } - case "Realm": - // panic if got unexpected error - if pnc != nil { - if tv, ok := pnc.(*gno.TypedValue); ok { - panic(fmt.Sprintf("fail on %s: got unexpected error: %s", path, tv.Sprint(m))) - } else { // TODO: does this happen? - panic(fmt.Sprintf("fail on %s: got unexpected error: %v", path, pnc)) - } - } - // check realm ops - if rops != "" { - rops2 := strings.TrimSpace(store.SprintStoreOps()) - if rops != rops2 { - if f.syncWanted { - // write output to file. - replaceWantedInPlace(path, "Realm", rops2) - } else { - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(rops), - B: difflib.SplitLines(rops2), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) - } - } - } - case "Preprocessed": - // check preprocessed AST. - pn := store.GetBlockNode(gno.PackageNodeLocation(pkgPath)) - pre := pn.(*gno.PackageNode).FileSet.Files[0].String() - if pre != preWanted { - if f.syncWanted { - // write error to file - replaceWantedInPlace(path, "Preprocessed", pre) - } else { - // panic so tests immediately fail (for now). - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(preWanted), - B: difflib.SplitLines(pre), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) - } - } - case "Stacktrace": - if stacktraceWanted != "" { - var stacktrace string - - switch pnc.(type) { - case gno.UnhandledPanicError: - stacktrace = m.ExceptionsStacktrace() - default: - stacktrace = m.Stacktrace().String() - } - - if f.syncWanted { - // write stacktrace to file - replaceWantedInPlace(path, "Stacktrace", stacktrace) - } else { - if !strings.Contains(stacktrace, stacktraceWanted) { - diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ - A: difflib.SplitLines(stacktraceWanted), - B: difflib.SplitLines(stacktrace), - FromFile: "Expected", - FromDate: "", - ToFile: "Actual", - ToDate: "", - Context: 1, - }) - panic(fmt.Sprintf("fail on %s: diff:\n%s\n", path, diff)) - } - } - } - checkMachineIsEmpty = false - default: - return nil - } - } - } - - if checkMachineIsEmpty { - // Check that machine is empty. - err = m.CheckEmpty() - if err != nil { - if f.logger != nil { - f.logger("last state: \n", m.String()) - } - panic(fmt.Sprintf("fail on %s: machine not empty after main: %v", path, err)) - } - } - return nil -} - -func wantedFromComment(p string) (directives []string, pkgPath, res, err, rops, events, stacktrace string, maxAlloc int64, send std.Coins, pre string) { - fset := token.NewFileSet() - f, err2 := parser.ParseFile(fset, p, nil, parser.ParseComments) - if err2 != nil { - panic(err2) - } - if len(f.Comments) == 0 { - return - } - for _, comments := range f.Comments { - text := readComments(comments) - if strings.HasPrefix(text, "PKGPATH:") { - line := strings.SplitN(text, "\n", 2)[0] - pkgPath = strings.TrimSpace(strings.TrimPrefix(line, "PKGPATH:")) - } else if strings.HasPrefix(text, "MAXALLOC:") { - line := strings.SplitN(text, "\n", 2)[0] - maxstr := strings.TrimSpace(strings.TrimPrefix(line, "MAXALLOC:")) - maxint, err := strconv.Atoi(maxstr) - if err != nil { - panic(fmt.Sprintf("invalid maxalloc amount: %v", maxstr)) - } - maxAlloc = int64(maxint) - } else if strings.HasPrefix(text, "SEND:") { - line := strings.SplitN(text, "\n", 2)[0] - sendstr := strings.TrimSpace(strings.TrimPrefix(line, "SEND:")) - send = std.MustParseCoins(sendstr) - } else if strings.HasPrefix(text, "Output:\n") { - res = strings.TrimPrefix(text, "Output:\n") - res = strings.TrimSpace(res) - directives = append(directives, "Output") - } else if strings.HasPrefix(text, "Error:\n") { - err = strings.TrimPrefix(text, "Error:\n") - err = strings.TrimSpace(err) - // XXX temporary until we support line:column. - // If error starts with line:column, trim it. - re := regexp.MustCompile(`^[0-9]+:[0-9]+: `) - err = re.ReplaceAllString(err, "") - directives = append(directives, "Error") - } else if strings.HasPrefix(text, "Realm:\n") { - rops = strings.TrimPrefix(text, "Realm:\n") - rops = strings.TrimSpace(rops) - directives = append(directives, "Realm") - } else if strings.HasPrefix(text, "Events:\n") { - events = strings.TrimPrefix(text, "Events:\n") - events = strings.TrimSpace(events) - directives = append(directives, "Events") - } else if strings.HasPrefix(text, "Preprocessed:\n") { - pre = strings.TrimPrefix(text, "Preprocessed:\n") - pre = strings.TrimSpace(pre) - directives = append(directives, "Preprocessed") - } else if strings.HasPrefix(text, "Stacktrace:\n") { - stacktrace = strings.TrimPrefix(text, "Stacktrace:\n") - stacktrace = strings.TrimSpace(stacktrace) - directives = append(directives, "Stacktrace") - } else { - // ignore unexpected. - } - } - return -} - -// readComments returns //-style comments from cg, but without truncating empty -// lines like cg.Text(). -func readComments(cg *ast.CommentGroup) string { - var b strings.Builder - for _, c := range cg.List { - if len(c.Text) < 2 || c.Text[:2] != "//" { - // ignore no //-style comment - break - } - s := strings.TrimPrefix(c.Text[2:], " ") - b.WriteString(s + "\n") - } - return b.String() -} - -// Replace comment in file with given output given directive. -func replaceWantedInPlace(path string, directive string, output string) { - bz := osm.MustReadFile(path) - body := string(bz) - lines := strings.Split(body, "\n") - isReplacing := false - wroteDirective := false - newlines := []string(nil) - for _, line := range lines { - if line == "// "+directive+":" { - if wroteDirective { - isReplacing = true - continue - } else { - wroteDirective = true - isReplacing = true - newlines = append(newlines, "// "+directive+":") - outlines := strings.Split(output, "\n") - for _, outline := range outlines { - newlines = append(newlines, - strings.TrimRight("// "+outline, " ")) - } - continue - } - } else if isReplacing { - if strings.HasPrefix(line, "//") { - continue - } else { - isReplacing = false - } - } - newlines = append(newlines, line) - } - osm.MustWriteFile(path, []byte(strings.Join(newlines, "\n")), 0o644) -} - -func DefaultPkgName(gopkgPath string) gno.Name { - parts := strings.Split(gopkgPath, "/") - last := parts[len(parts)-1] - parts = strings.Split(last, "-") - name := parts[len(parts)-1] - name = strings.ToLower(name) - return gno.Name(name) -} - -// go comments strip trailing spaces. -func trimTrailingSpaces(result string) string { - lines := strings.Split(result, "\n") - for i, line := range lines { - lines[i] = strings.TrimRight(line, " \t") - } - return strings.Join(lines, "\n") -} - -// ---------------------------------------- -// testParams -type testParams struct{} - -func newTestParams() *testParams { - return &testParams{} -} - -func (tp *testParams) SetBool(key string, val bool) { /* noop */ } -func (tp *testParams) SetBytes(key string, val []byte) { /* noop */ } -func (tp *testParams) SetInt64(key string, val int64) { /* noop */ } -func (tp *testParams) SetUint64(key string, val uint64) { /* noop */ } -func (tp *testParams) SetString(key string, val string) { /* noop */ } - -// ---------------------------------------- -// testBanker - -type testBanker struct { - coinTable map[crypto.Bech32Address]std.Coins -} - -func newTestBanker(args ...interface{}) *testBanker { - coinTable := make(map[crypto.Bech32Address]std.Coins) - if len(args)%2 != 0 { - panic("newTestBanker requires even number of arguments; addr followed by coins") - } - for i := 0; i < len(args); i += 2 { - addr := args[i].(crypto.Bech32Address) - amount := args[i+1].(std.Coins) - coinTable[addr] = amount - } - return &testBanker{ - coinTable: coinTable, - } -} - -func (tb *testBanker) GetCoins(addr crypto.Bech32Address) (dst std.Coins) { - return tb.coinTable[addr] -} - -func (tb *testBanker) SendCoins(from, to crypto.Bech32Address, amt std.Coins) { - fcoins, fexists := tb.coinTable[from] - if !fexists { - panic(fmt.Sprintf( - "source address %s does not exist", - from.String())) - } - if !fcoins.IsAllGTE(amt) { - panic(fmt.Sprintf( - "source address %s has %s; cannot send %s", - from.String(), fcoins, amt)) - } - // First, subtract from 'from'. - frest := fcoins.Sub(amt) - tb.coinTable[from] = frest - // Second, add to 'to'. - // NOTE: even works when from==to, due to 2-step isolation. - tcoins, _ := tb.coinTable[to] - tsum := tcoins.Add(amt) - tb.coinTable[to] = tsum -} - -func (tb *testBanker) TotalCoin(denom string) int64 { - panic("not yet implemented") -} - -func (tb *testBanker) IssueCoin(addr crypto.Bech32Address, denom string, amt int64) { - coins, _ := tb.coinTable[addr] - sum := coins.Add(std.Coins{{Denom: denom, Amount: amt}}) - tb.coinTable[addr] = sum -} - -func (tb *testBanker) RemoveCoin(addr crypto.Bech32Address, denom string, amt int64) { - coins, _ := tb.coinTable[addr] - rest := coins.Sub(std.Coins{{Denom: denom, Amount: amt}}) - tb.coinTable[addr] = rest -} diff --git a/gnovm/tests/file_test.go b/gnovm/tests/file_test.go deleted file mode 100644 index 4313fd88645..00000000000 --- a/gnovm/tests/file_test.go +++ /dev/null @@ -1,144 +0,0 @@ -package tests - -import ( - "flag" - "io/fs" - "os" - "path" - "path/filepath" - "strings" - "testing" - - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" -) - -var withSync = flag.Bool("update-golden-tests", false, "rewrite tests updating Realm: and Output: with new values where changed") - -func TestFileStr(t *testing.T) { - filePath := filepath.Join(".", "files", "str.gno") - runFileTest(t, filePath, WithNativeLibs()) -} - -// Run tests in the `files` directory using shims from stdlib -// to native go standard library. -func TestFilesNative(t *testing.T) { - baseDir := filepath.Join(".", "files") - runFileTests(t, baseDir, []string{"*_stdlibs*"}, WithNativeLibs()) -} - -// Test files using standard library in stdlibs/. -func TestFiles(t *testing.T) { - baseDir := filepath.Join(".", "files") - runFileTests(t, baseDir, []string{"*_native*"}) -} - -func TestChallenges(t *testing.T) { - t.Skip("Challenge tests, skipping.") - baseDir := filepath.Join(".", "challenges") - runFileTests(t, baseDir, nil) -} - -type testFile struct { - path string - fs.DirEntry -} - -// ignore are glob patterns to ignore -func runFileTests(t *testing.T, baseDir string, ignore []string, opts ...RunFileTestOption) { - t.Helper() - - opts = append([]RunFileTestOption{WithSyncWanted(*withSync)}, opts...) - - files, err := readFiles(t, baseDir) - if err != nil { - t.Fatal(err) - } - - files = filterFileTests(t, files, ignore) - var path string - var name string - for _, file := range files { - path = file.path - name = strings.TrimPrefix(file.path, baseDir+string(os.PathSeparator)) - t.Run(name, func(t *testing.T) { - runFileTest(t, path, opts...) - }) - } -} - -// it reads all files recursively in the directory -func readFiles(t *testing.T, dir string) ([]testFile, error) { - t.Helper() - var files []testFile - - err := filepath.WalkDir(dir, func(path string, de fs.DirEntry, err error) error { - if err != nil { - return err - } - if de.IsDir() && de.Name() == "extern" { - return filepath.SkipDir - } - f := testFile{path: path, DirEntry: de} - - files = append(files, f) - return nil - }) - return files, err -} - -func filterFileTests(t *testing.T, files []testFile, ignore []string) []testFile { - t.Helper() - filtered := make([]testFile, 0, 1000) - var name string - - for _, f := range files { - // skip none .gno files - name = f.DirEntry.Name() - if filepath.Ext(name) != ".gno" { - continue - } - // skip ignored files - if isIgnored(t, name, ignore) { - continue - } - // skip _long file if we only want to test regular file. - if testing.Short() && strings.Contains(name, "_long") { - t.Logf("skipping test %s in short mode.", name) - continue - } - filtered = append(filtered, f) - } - return filtered -} - -func isIgnored(t *testing.T, name string, ignore []string) bool { - t.Helper() - isIgnore := false - for _, is := range ignore { - match, err := path.Match(is, name) - if err != nil { - t.Fatalf("error parsing glob pattern %q: %v", is, err) - } - if match { - isIgnore = true - break - } - } - return isIgnore -} - -func runFileTest(t *testing.T, path string, opts ...RunFileTestOption) { - t.Helper() - - opts = append([]RunFileTestOption{WithSyncWanted(*withSync)}, opts...) - - var logger loggerFunc - if gno.IsDebug() && testing.Verbose() { - logger = t.Log - } - rootDir := filepath.Join("..", "..") - err := RunFileTest(rootDir, path, append(opts, WithLoggerFunc(logger))...) - if err != nil { - t.Fatalf("got error: %v", err) - } -} diff --git a/gnovm/tests/files/access0_stdlibs.gno b/gnovm/tests/files/access0.gno similarity index 100% rename from gnovm/tests/files/access0_stdlibs.gno rename to gnovm/tests/files/access0.gno diff --git a/gnovm/tests/files/access1_stdlibs.gno b/gnovm/tests/files/access1.gno similarity index 52% rename from gnovm/tests/files/access1_stdlibs.gno rename to gnovm/tests/files/access1.gno index 5a1bf4cc12e..bcbfdb2829c 100644 --- a/gnovm/tests/files/access1_stdlibs.gno +++ b/gnovm/tests/files/access1.gno @@ -9,4 +9,4 @@ func main() { } // Error: -// main/files/access1_stdlibs.gno:8:10: cannot access gno.land/p/demo/testutils.testVar2 from main +// main/files/access1.gno:8:10: cannot access gno.land/p/demo/testutils.testVar2 from main diff --git a/gnovm/tests/files/access2_stdlibs.gno b/gnovm/tests/files/access2.gno similarity index 100% rename from gnovm/tests/files/access2_stdlibs.gno rename to gnovm/tests/files/access2.gno diff --git a/gnovm/tests/files/access3_stdlibs.gno b/gnovm/tests/files/access3.gno similarity index 100% rename from gnovm/tests/files/access3_stdlibs.gno rename to gnovm/tests/files/access3.gno diff --git a/gnovm/tests/files/access4_stdlibs.gno b/gnovm/tests/files/access4.gno similarity index 56% rename from gnovm/tests/files/access4_stdlibs.gno rename to gnovm/tests/files/access4.gno index e38a6d2ea4a..72c4f926ce4 100644 --- a/gnovm/tests/files/access4_stdlibs.gno +++ b/gnovm/tests/files/access4.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/access4_stdlibs.gno:9:10: cannot access gno.land/p/demo/testutils.TestAccessStruct.privateField from main +// main/files/access4.gno:9:10: cannot access gno.land/p/demo/testutils.TestAccessStruct.privateField from main diff --git a/gnovm/tests/files/access5_stdlibs.gno b/gnovm/tests/files/access5.gno similarity index 100% rename from gnovm/tests/files/access5_stdlibs.gno rename to gnovm/tests/files/access5.gno diff --git a/gnovm/tests/files/access6_stdlibs.gno b/gnovm/tests/files/access6.gno similarity index 61% rename from gnovm/tests/files/access6_stdlibs.gno rename to gnovm/tests/files/access6.gno index 443f2f5291d..04778a8f5bb 100644 --- a/gnovm/tests/files/access6_stdlibs.gno +++ b/gnovm/tests/files/access6.gno @@ -16,4 +16,4 @@ func main() { } // Error: -// main/files/access6_stdlibs.gno:15:2: main.mystruct does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) +// main/files/access6.gno:15:2: main.mystruct does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) diff --git a/gnovm/tests/files/access7_stdlibs.gno b/gnovm/tests/files/access7.gno similarity index 67% rename from gnovm/tests/files/access7_stdlibs.gno rename to gnovm/tests/files/access7.gno index 01c9ed83fa0..3874ad98971 100644 --- a/gnovm/tests/files/access7_stdlibs.gno +++ b/gnovm/tests/files/access7.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/access7_stdlibs.gno:19:2: main.PrivateInterface2 does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) +// main/files/access7.gno:19:2: main.PrivateInterface2 does not implement gno.land/p/demo/testutils.PrivateInterface (missing method privateMethod) diff --git a/gnovm/tests/files/addr0b_stdlibs.gno b/gnovm/tests/files/addr0b.gno similarity index 100% rename from gnovm/tests/files/addr0b_stdlibs.gno rename to gnovm/tests/files/addr0b.gno diff --git a/gnovm/tests/files/addr0b_native.gno b/gnovm/tests/files/addr0b_native.gno deleted file mode 100644 index 86846500e42..00000000000 --- a/gnovm/tests/files/addr0b_native.gno +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/gnolang/gno/_test/net/http" -) - -type extendedRequest struct { - Request http.Request - - Data string -} - -func main() { - r := extendedRequest{} - req := &r.Request - - fmt.Println(r) - fmt.Println(req) -} - -// Output: -// {{ 0 0 map[] 0 [] false map[] map[] map[] } } -// &{ 0 0 map[] 0 [] false map[] map[] map[] } diff --git a/gnovm/tests/files/addr2b.gno b/gnovm/tests/files/addr2b.gno index 04342c00574..59a18904bea 100644 --- a/gnovm/tests/files/addr2b.gno +++ b/gnovm/tests/files/addr2b.gno @@ -1,24 +1,22 @@ package main import ( - "encoding/xml" + "encoding/json" "fmt" ) type Email struct { - Where string `xml:"where,attr"` + Where string Addr string } func f(s string, r interface{}) interface{} { - return xml.Unmarshal([]byte(s), &r) + return json.Unmarshal([]byte(s), &r) } func main() { data := ` - - bob@work.com - + {"Where": "work", "Addr": "bob@work.com"} ` v := Email{} err := f(data, &v) diff --git a/gnovm/tests/files/assign0b_stdlibs.gno b/gnovm/tests/files/assign0b.gno similarity index 100% rename from gnovm/tests/files/assign0b_stdlibs.gno rename to gnovm/tests/files/assign0b.gno diff --git a/gnovm/tests/files/assign0b_native.gno b/gnovm/tests/files/assign0b_native.gno deleted file mode 100644 index 42faa57634d..00000000000 --- a/gnovm/tests/files/assign0b_native.gno +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "github.com/gnolang/gno/_test/net/http" -) - -func main() { - http.DefaultClient.Timeout = time.Second * 10 - fmt.Println(http.DefaultClient) - http.DefaultClient = &http.Client{} - fmt.Println(http.DefaultClient) -} - -// Output: -// &{ 10s} -// &{ 0s} diff --git a/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest_stdlibs.gno b/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno similarity index 100% rename from gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest_stdlibs.gno rename to gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index d61170334d7..45f83bade5f 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -210,7 +210,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "files/assign_unnamed_type/more/realm_compositelit.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", @@ -221,7 +221,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "files/assign_unnamed_type/more/realm_compositelit.gno", // "Line": "16", // "PkgPath": "gno.land/r/test" // } diff --git a/gnovm/tests/files/bin1.gno b/gnovm/tests/files/bin1.gno index 792651f60bf..e0e5a6d663a 100644 --- a/gnovm/tests/files/bin1.gno +++ b/gnovm/tests/files/bin1.gno @@ -1,16 +1,14 @@ package main import ( - "crypto/sha1" + "crypto/sha256" "fmt" ) func main() { - d := sha1.New() - d.Write([]byte("password")) - a := d.Sum(nil) + a := sha256.Sum256([]byte("password")) fmt.Println(a) } // Output: -// [91 170 97 228 201 185 63 63 6 130 37 11 108 248 51 27 126 230 143 216] +// [94 136 72 152 218 40 4 113 81 208 229 111 141 198 41 39 115 96 61 13 106 171 189 214 42 17 239 114 29 21 66 216] diff --git a/gnovm/tests/files/bin5.gno b/gnovm/tests/files/bin5.gno deleted file mode 100644 index d471d4e0fd2..00000000000 --- a/gnovm/tests/files/bin5.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "net" -) - -func main() { - addr := net.TCPAddr{IP: net.IPv4(1, 1, 1, 1), Port: 80} - var s fmt.Stringer = &addr - fmt.Println(s.String()) -} - -// Output: -// 1.1.1.1:80 diff --git a/gnovm/tests/files/binstruct_ptr_map0.gno b/gnovm/tests/files/binstruct_ptr_map0.gno index 329ece209e4..5eddca44f6e 100644 --- a/gnovm/tests/files/binstruct_ptr_map0.gno +++ b/gnovm/tests/files/binstruct_ptr_map0.gno @@ -2,11 +2,12 @@ package main import ( "fmt" - "image" ) +type Point struct{ X, Y int } + func main() { - v := map[string]*image.Point{ + v := map[string]*Point{ "foo": {X: 3, Y: 2}, "bar": {X: 4, Y: 5}, } @@ -14,4 +15,4 @@ func main() { } // Output: -// (3,2) (4,5) +// &{3 2} &{4 5} diff --git a/gnovm/tests/files/binstruct_ptr_slice0.gno b/gnovm/tests/files/binstruct_ptr_slice0.gno deleted file mode 100644 index 1ceea6cab70..00000000000 --- a/gnovm/tests/files/binstruct_ptr_slice0.gno +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "fmt" - "image" -) - -func main() { - v := []*image.Point{ - {X: 3, Y: 2}, - {X: 4, Y: 5}, - } - fmt.Println(v) -} - -// Output: -// [(3,2) (4,5)] diff --git a/gnovm/tests/files/binstruct_slice0.gno b/gnovm/tests/files/binstruct_slice0.gno index 211f60faf01..3cdc455a66f 100644 --- a/gnovm/tests/files/binstruct_slice0.gno +++ b/gnovm/tests/files/binstruct_slice0.gno @@ -2,15 +2,16 @@ package main import ( "fmt" - "image" ) +type Point struct{ X, Y int } + func main() { - v := []image.Point{ + v := []Point{ {X: 3, Y: 2}, } fmt.Println(v) } // Output: -// [(3,2)] +// [{3 2}] diff --git a/gnovm/tests/files/composite11.gno b/gnovm/tests/files/composite11.gno index 85f71018202..2d989022f25 100644 --- a/gnovm/tests/files/composite11.gno +++ b/gnovm/tests/files/composite11.gno @@ -2,11 +2,14 @@ package main import ( "fmt" - "image/color" ) +type NRGBA64 struct { + R, G, B, A uint16 +} + func main() { - c := color.NRGBA64{1, 1, 1, 1} + c := NRGBA64{1, 1, 1, 1} fmt.Println(c) } diff --git a/gnovm/tests/files/const14.gno b/gnovm/tests/files/const14.gno index 835858f712d..93d7975e20f 100644 --- a/gnovm/tests/files/const14.gno +++ b/gnovm/tests/files/const14.gno @@ -1,13 +1,13 @@ package main -import "compress/flate" +import "math" -func f1(i int) { println("i:", i) } +func f1(i float64) { println("i:", i) } func main() { - i := flate.BestSpeed + i := math.Pi f1(i) } // Output: -// i: 1 +// i: 3.141592653589793 diff --git a/gnovm/tests/files/const22.gno b/gnovm/tests/files/const22.gno index 42842066265..f92fcd4d910 100644 --- a/gnovm/tests/files/const22.gno +++ b/gnovm/tests/files/const22.gno @@ -31,7 +31,7 @@ func main() { fmt.Printf("%x", ha) fmt.Printf("%x", hb) - fmt.Printf("%x", ho) + fmt.Printf("%x\n", ho) } // Output: diff --git a/gnovm/tests/files/context.gno b/gnovm/tests/files/context.gno deleted file mode 100644 index 0dcd8d73a22..00000000000 --- a/gnovm/tests/files/context.gno +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import "context" - -func get(ctx context.Context, k string) string { - var r string - if v := ctx.Value(k); v != nil { - r = v.(string) - } - return r -} - -func main() { - ctx := context.WithValue(context.Background(), "hello", "world") - println(get(ctx, "hello")) -} - -// Output: -// world diff --git a/gnovm/tests/files/context2.gno b/gnovm/tests/files/context2.gno deleted file mode 100644 index 457fb03b735..00000000000 --- a/gnovm/tests/files/context2.gno +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import "context" - -func get(ctx context.Context, k string) string { - var r string - var ok bool - if v := ctx.Value(k); v != nil { - r, ok = v.(string) - println(ok) - } - return r -} - -func main() { - ctx := context.WithValue(context.Background(), "hello", "world") - println(get(ctx, "hello")) -} - -// Output: -// true -// world diff --git a/gnovm/tests/files/defer4.gno b/gnovm/tests/files/defer4.gno deleted file mode 100644 index e9baa5ac250..00000000000 --- a/gnovm/tests/files/defer4.gno +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import "sync" - -type T struct { - mu sync.RWMutex - name string -} - -func (t *T) get() string { - t.mu.RLock() - defer t.mu.RUnlock() - return t.name -} - -var d = T{name: "test"} - -func main() { - println(d.get()) -} - -// Output: -// test diff --git a/gnovm/tests/files/extern/p1/s1.gno b/gnovm/tests/files/extern/p1/s1.gno deleted file mode 100644 index ff2d89d4462..00000000000 --- a/gnovm/tests/files/extern/p1/s1.gno +++ /dev/null @@ -1,5 +0,0 @@ -package p1 - -import "crypto/rand" - -var Prime = rand.Prime diff --git a/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno b/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno index 2411bd2081f..13f94950dfa 100644 --- a/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno +++ b/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno @@ -2,7 +2,7 @@ package types import ( "bytes" - "hash/fnv" + "crypto/sha256" ) type ( @@ -36,9 +36,7 @@ func (self String) Less(other Sortable) bool { } func (self String) Hash() int { - h := fnv.New32a() - h.Write([]byte(string(self))) - return int(h.Sum32()) + return int(hash([]byte(self))) } func (self *ByteSlice) MarshalBinary() ([]byte, error) { @@ -67,7 +65,13 @@ func (self ByteSlice) Less(other Sortable) bool { } func (self ByteSlice) Hash() int { - h := fnv.New32a() - h.Write([]byte(self)) - return int(h.Sum32()) + return int(hash([]byte(self))) +} + +func hash(s []byte) int { + res := sha256.Sum256(s) + return int(s[0]) | + int(s[1]<<8) | + int(s[2]<<16) | + int(s[3]<<24) } diff --git a/gnovm/tests/files/float5_stdlibs.gno b/gnovm/tests/files/float5.gno similarity index 100% rename from gnovm/tests/files/float5_stdlibs.gno rename to gnovm/tests/files/float5.gno diff --git a/gnovm/tests/files/fun6.gno b/gnovm/tests/files/fun6.gno deleted file mode 100644 index c5ec644afd5..00000000000 --- a/gnovm/tests/files/fun6.gno +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "fmt" - "sync" -) - -func NewPool() Pool { return Pool{} } - -type Pool struct { - P *sync.Pool -} - -var _pool = NewPool() - -func main() { - fmt.Println(_pool) -} - -// Output: -// {} diff --git a/gnovm/tests/files/fun6b.gno b/gnovm/tests/files/fun6b.gno deleted file mode 100644 index 17b0473b33b..00000000000 --- a/gnovm/tests/files/fun6b.gno +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "sync" -) - -func NewPool() Pool { return Pool{} } - -type Pool struct { - p *sync.Pool -} - -var _pool = NewPool() - -func main() { - println(_pool) -} - -// Output: -// (struct{(gonative{} gonative{*sync.Pool})} main.Pool) diff --git a/gnovm/tests/files/fun7.gno b/gnovm/tests/files/fun7.gno deleted file mode 100644 index ee8f813a527..00000000000 --- a/gnovm/tests/files/fun7.gno +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - goflag "flag" - "fmt" -) - -func Foo(goflag *goflag.Flag) { - fmt.Println(goflag) -} - -func main() { - g := &goflag.Flag{} - Foo(g) -} - -// Output: -// &{ } diff --git a/gnovm/tests/files/heap_alloc_forloop9_1.gno b/gnovm/tests/files/heap_alloc_forloop9_1.gno index 5e3b9af74f6..2576b9b4da6 100644 --- a/gnovm/tests/files/heap_alloc_forloop9_1.gno +++ b/gnovm/tests/files/heap_alloc_forloop9_1.gno @@ -19,7 +19,7 @@ func main() { // file{ package main; func Search(n (const-type int), f func(.arg_0 (const-type int)) (const-type bool)) (const-type int) { f((const (1 int))); return (const (0 int)) }; func main() { for x := (const (0 int)); x<~VPBlock(1,0)> < (const (2 int)); x<~VPBlock(1,0)>++ { count := (const (0 int)); (const (println func(xs ...interface{})()))((const (" first: count: " string)), count<~VPBlock(1,1)>); Search((const (1 int)), func func(i (const-type int)) (const-type bool){ count<~VPBlock(1,2)>++; return (const-type bool)(i >= x<~VPBlock(1,3)>) }, x<()~VPBlock(1,0)>>); (const (println func(xs ...interface{})()))((const ("second: count: " string)), count<~VPBlock(1,1)>) } } } // Output: -// first: count: 0 +// first: count: 0 // second: count: 1 // first: count: 0 // second: count: 1 diff --git a/gnovm/tests/files/heap_item_value.gno b/gnovm/tests/files/heap_item_value.gno index 40ec05d3ba1..80bf702bec2 100644 --- a/gnovm/tests/files/heap_item_value.gno +++ b/gnovm/tests/files/heap_item_value.gno @@ -151,7 +151,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "files/heap_item_value.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", @@ -162,7 +162,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "files/heap_item_value.gno", // "Line": "10", // "PkgPath": "gno.land/r/test" // } diff --git a/gnovm/tests/files/heap_item_value_init.gno b/gnovm/tests/files/heap_item_value_init.gno index 72f065326f1..2722cce8675 100644 --- a/gnovm/tests/files/heap_item_value_init.gno +++ b/gnovm/tests/files/heap_item_value_init.gno @@ -122,7 +122,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "files/heap_item_value_init.gno", // "IsMethod": false, // "Name": "init.3", // "NativeName": "", @@ -133,7 +133,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "files/heap_item_value_init.gno", // "Line": "10", // "PkgPath": "gno.land/r/test" // } @@ -158,7 +158,7 @@ func main() { // "Escaped": true, // "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" // }, -// "FileName": "main.gno", +// "FileName": "files/heap_item_value_init.gno", // "IsMethod": false, // "Name": "main", // "NativeName": "", @@ -169,7 +169,7 @@ func main() { // "BlockNode": null, // "Location": { // "Column": "1", -// "File": "main.gno", +// "File": "files/heap_item_value_init.gno", // "Line": "16", // "PkgPath": "gno.land/r/test" // } diff --git a/gnovm/tests/files/import3.gno b/gnovm/tests/files/import3.gno index c16ac626299..c63ed8a055c 100644 --- a/gnovm/tests/files/import3.gno +++ b/gnovm/tests/files/import3.gno @@ -4,7 +4,8 @@ import "github.com/gnolang/gno/_test/foo" func main() { println(foo.Bar, foo.Boo) } +// Init functions of dependencies are executed separatedly from the test itself, +// so they don't print with the test proper. + // Output: -// init boo -// init foo // BARR Boo diff --git a/gnovm/tests/files/import5.gno b/gnovm/tests/files/import5.gno index 609364d85b1..b270d0b0d3c 100644 --- a/gnovm/tests/files/import5.gno +++ b/gnovm/tests/files/import5.gno @@ -5,6 +5,4 @@ import boo "github.com/gnolang/gno/_test/foo" func main() { println(boo.Bar, boo.Boo, boo.Bir) } // Output: -// init boo -// init foo // BARR Boo Boo22 diff --git a/gnovm/tests/files/interp.gi b/gnovm/tests/files/interp.gi deleted file mode 100644 index ace895a356c..00000000000 --- a/gnovm/tests/files/interp.gi +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "github.com/gnolang/gno/interp" -) - -func main() { - i := interp.New(interp.Opt{}) - i.Eval(`println("Hello")`) -} - -// Output: -// Hello diff --git a/gnovm/tests/files/interp2.gi b/gnovm/tests/files/interp2.gi deleted file mode 100644 index af3ffd75f18..00000000000 --- a/gnovm/tests/files/interp2.gi +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "github.com/gnolang/gno/interp" -) - -func main() { - i := interp.New(interp.Opt{}) - i.Use(interp.ExportValue, interp.ExportType) - i.Eval(`import "github.com/gnolang/gno/interp"`) - i.Eval(`i := interp.New(interp.Opt{})`) - i.Eval(`i.Eval("println(42)")`) -} - -// Output: -// 42 diff --git a/gnovm/tests/files/io0_stdlibs.gno b/gnovm/tests/files/io0.gno similarity index 100% rename from gnovm/tests/files/io0_stdlibs.gno rename to gnovm/tests/files/io0.gno diff --git a/gnovm/tests/files/io0_native.gno b/gnovm/tests/files/io0_native.gno deleted file mode 100644 index 6486a9ba558..00000000000 --- a/gnovm/tests/files/io0_native.gno +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "crypto/rand" - "fmt" - "io" -) - -func main() { - var buf [16]byte - fmt.Println(buf) - io.ReadFull(rand.Reader, buf[:]) - fmt.Println(buf) -} - -// Output: -// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] -// [100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115] diff --git a/gnovm/tests/files/io2.gno b/gnovm/tests/files/io2.gno index 24655f5040c..d0637c44e16 100644 --- a/gnovm/tests/files/io2.gno +++ b/gnovm/tests/files/io2.gno @@ -3,7 +3,6 @@ package main import ( "fmt" "io" - "log" "strings" ) @@ -12,9 +11,9 @@ func main() { b, err := io.ReadAll(r) if err != nil { - log.Fatal(err) + panic(err) } - fmt.Printf("%s", b) + fmt.Printf("%s\n", b) } // Output: diff --git a/gnovm/tests/files/issue_558b_stdlibs.gno b/gnovm/tests/files/issue_558b.gno similarity index 97% rename from gnovm/tests/files/issue_558b_stdlibs.gno rename to gnovm/tests/files/issue_558b.gno index 55eba88c985..51ddee56e0a 100644 --- a/gnovm/tests/files/issue_558b_stdlibs.gno +++ b/gnovm/tests/files/issue_558b.gno @@ -3,8 +3,6 @@ package main import ( "fmt" "io" - "io" - "log" "strings" ) @@ -68,7 +66,7 @@ func main() { p.Reader = newReadAutoCloser(strings.NewReader("test")) b, err := ReadAll(p.Reader) if err != nil { - log.Fatal(err) + panic(err) } fmt.Println(string(b)) } diff --git a/gnovm/tests/files/issue_782.gno b/gnovm/tests/files/issue_782.gno index 9d89a90bd30..4dc938ceaec 100644 --- a/gnovm/tests/files/issue_782.gno +++ b/gnovm/tests/files/issue_782.gno @@ -7,7 +7,7 @@ func main() { from := uint32(2) to := uint32(4) b := a[from:to] - fmt.Print(b) + fmt.Println(b) } // Output: diff --git a/gnovm/tests/files/l3_long.gno b/gnovm/tests/files/l3_long.gno deleted file mode 100644 index 64e75f522b2..00000000000 --- a/gnovm/tests/files/l3_long.gno +++ /dev/null @@ -1,163 +0,0 @@ -package main - -func main() { - for a := 0; a < 20000000; a++ { - if a&0x8ffff == 0x80000 { - println(a) - } - } -} - -// Output: -// 524288 -// 589824 -// 655360 -// 720896 -// 786432 -// 851968 -// 917504 -// 983040 -// 1572864 -// 1638400 -// 1703936 -// 1769472 -// 1835008 -// 1900544 -// 1966080 -// 2031616 -// 2621440 -// 2686976 -// 2752512 -// 2818048 -// 2883584 -// 2949120 -// 3014656 -// 3080192 -// 3670016 -// 3735552 -// 3801088 -// 3866624 -// 3932160 -// 3997696 -// 4063232 -// 4128768 -// 4718592 -// 4784128 -// 4849664 -// 4915200 -// 4980736 -// 5046272 -// 5111808 -// 5177344 -// 5767168 -// 5832704 -// 5898240 -// 5963776 -// 6029312 -// 6094848 -// 6160384 -// 6225920 -// 6815744 -// 6881280 -// 6946816 -// 7012352 -// 7077888 -// 7143424 -// 7208960 -// 7274496 -// 7864320 -// 7929856 -// 7995392 -// 8060928 -// 8126464 -// 8192000 -// 8257536 -// 8323072 -// 8912896 -// 8978432 -// 9043968 -// 9109504 -// 9175040 -// 9240576 -// 9306112 -// 9371648 -// 9961472 -// 10027008 -// 10092544 -// 10158080 -// 10223616 -// 10289152 -// 10354688 -// 10420224 -// 11010048 -// 11075584 -// 11141120 -// 11206656 -// 11272192 -// 11337728 -// 11403264 -// 11468800 -// 12058624 -// 12124160 -// 12189696 -// 12255232 -// 12320768 -// 12386304 -// 12451840 -// 12517376 -// 13107200 -// 13172736 -// 13238272 -// 13303808 -// 13369344 -// 13434880 -// 13500416 -// 13565952 -// 14155776 -// 14221312 -// 14286848 -// 14352384 -// 14417920 -// 14483456 -// 14548992 -// 14614528 -// 15204352 -// 15269888 -// 15335424 -// 15400960 -// 15466496 -// 15532032 -// 15597568 -// 15663104 -// 16252928 -// 16318464 -// 16384000 -// 16449536 -// 16515072 -// 16580608 -// 16646144 -// 16711680 -// 17301504 -// 17367040 -// 17432576 -// 17498112 -// 17563648 -// 17629184 -// 17694720 -// 17760256 -// 18350080 -// 18415616 -// 18481152 -// 18546688 -// 18612224 -// 18677760 -// 18743296 -// 18808832 -// 19398656 -// 19464192 -// 19529728 -// 19595264 -// 19660800 -// 19726336 -// 19791872 -// 19857408 diff --git a/gnovm/tests/files/l4_long.gno b/gnovm/tests/files/l4_long.gno deleted file mode 100644 index f91542999b3..00000000000 --- a/gnovm/tests/files/l4_long.gno +++ /dev/null @@ -1,7 +0,0 @@ -package main - -func main() { println(f(5)) } -func f(i int) int { return i + 1 } - -// Output: -// 6 diff --git a/gnovm/tests/files/l5_long.gno b/gnovm/tests/files/l5_long.gno deleted file mode 100644 index c72357d2e15..00000000000 --- a/gnovm/tests/files/l5_long.gno +++ /dev/null @@ -1,164 +0,0 @@ -package main - -func main() { - for a := 0; a < 20000000; { - if a&0x8ffff == 0x80000 { - println(a) - } - a = a + 1 - } -} - -// Output: -// 524288 -// 589824 -// 655360 -// 720896 -// 786432 -// 851968 -// 917504 -// 983040 -// 1572864 -// 1638400 -// 1703936 -// 1769472 -// 1835008 -// 1900544 -// 1966080 -// 2031616 -// 2621440 -// 2686976 -// 2752512 -// 2818048 -// 2883584 -// 2949120 -// 3014656 -// 3080192 -// 3670016 -// 3735552 -// 3801088 -// 3866624 -// 3932160 -// 3997696 -// 4063232 -// 4128768 -// 4718592 -// 4784128 -// 4849664 -// 4915200 -// 4980736 -// 5046272 -// 5111808 -// 5177344 -// 5767168 -// 5832704 -// 5898240 -// 5963776 -// 6029312 -// 6094848 -// 6160384 -// 6225920 -// 6815744 -// 6881280 -// 6946816 -// 7012352 -// 7077888 -// 7143424 -// 7208960 -// 7274496 -// 7864320 -// 7929856 -// 7995392 -// 8060928 -// 8126464 -// 8192000 -// 8257536 -// 8323072 -// 8912896 -// 8978432 -// 9043968 -// 9109504 -// 9175040 -// 9240576 -// 9306112 -// 9371648 -// 9961472 -// 10027008 -// 10092544 -// 10158080 -// 10223616 -// 10289152 -// 10354688 -// 10420224 -// 11010048 -// 11075584 -// 11141120 -// 11206656 -// 11272192 -// 11337728 -// 11403264 -// 11468800 -// 12058624 -// 12124160 -// 12189696 -// 12255232 -// 12320768 -// 12386304 -// 12451840 -// 12517376 -// 13107200 -// 13172736 -// 13238272 -// 13303808 -// 13369344 -// 13434880 -// 13500416 -// 13565952 -// 14155776 -// 14221312 -// 14286848 -// 14352384 -// 14417920 -// 14483456 -// 14548992 -// 14614528 -// 15204352 -// 15269888 -// 15335424 -// 15400960 -// 15466496 -// 15532032 -// 15597568 -// 15663104 -// 16252928 -// 16318464 -// 16384000 -// 16449536 -// 16515072 -// 16580608 -// 16646144 -// 16711680 -// 17301504 -// 17367040 -// 17432576 -// 17498112 -// 17563648 -// 17629184 -// 17694720 -// 17760256 -// 18350080 -// 18415616 -// 18481152 -// 18546688 -// 18612224 -// 18677760 -// 18743296 -// 18808832 -// 19398656 -// 19464192 -// 19529728 -// 19595264 -// 19660800 -// 19726336 -// 19791872 -// 19857408 diff --git a/gnovm/tests/files/l2_long.gno b/gnovm/tests/files/loop0.gno similarity index 100% rename from gnovm/tests/files/l2_long.gno rename to gnovm/tests/files/loop0.gno diff --git a/gnovm/tests/files/loop1.gno b/gnovm/tests/files/loop1.gno new file mode 100644 index 00000000000..4a61fbfba5b --- /dev/null +++ b/gnovm/tests/files/loop1.gno @@ -0,0 +1,51 @@ +package main + +func main() { + for a := 0; a < 20000; { + if (a & 0x8ff) == 0x800 { + println(a) + } + a = a + 1 + } +} + +// Output: +// 2048 +// 2304 +// 2560 +// 2816 +// 3072 +// 3328 +// 3584 +// 3840 +// 6144 +// 6400 +// 6656 +// 6912 +// 7168 +// 7424 +// 7680 +// 7936 +// 10240 +// 10496 +// 10752 +// 11008 +// 11264 +// 11520 +// 11776 +// 12032 +// 14336 +// 14592 +// 14848 +// 15104 +// 15360 +// 15616 +// 15872 +// 16128 +// 18432 +// 18688 +// 18944 +// 19200 +// 19456 +// 19712 +// 19968 diff --git a/gnovm/tests/files/map27.gno b/gnovm/tests/files/map27.gno index 5d76ffc21c7..578788d144e 100644 --- a/gnovm/tests/files/map27.gno +++ b/gnovm/tests/files/map27.gno @@ -2,7 +2,6 @@ package main import ( "fmt" - "text/template" ) type fm map[string]interface{} @@ -14,7 +13,7 @@ func main() { a["foo"] = &foo{} fmt.Println(a["foo"]) - b := make(template.FuncMap) // type FuncMap map[string]interface{} + b := make(map[string]interface{}) b["foo"] = &foo{} fmt.Println(b["foo"]) } diff --git a/gnovm/tests/files/map29_stdlibs.gno b/gnovm/tests/files/map29.gno similarity index 100% rename from gnovm/tests/files/map29_stdlibs.gno rename to gnovm/tests/files/map29.gno diff --git a/gnovm/tests/files/map29_native.gno b/gnovm/tests/files/map29_native.gno deleted file mode 100644 index b4a4129cd39..00000000000 --- a/gnovm/tests/files/map29_native.gno +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -type Item struct { - Object interface{} - Expiry time.Duration -} - -func main() { - items := map[string]Item{} - - items["test"] = Item{ - Object: "test", - Expiry: time.Second, - } - - item := items["test"] - fmt.Println(item) -} - -// Output: -// {test 1s} diff --git a/gnovm/tests/files/math0_stdlibs.gno b/gnovm/tests/files/math0.gno similarity index 100% rename from gnovm/tests/files/math0_stdlibs.gno rename to gnovm/tests/files/math0.gno diff --git a/gnovm/tests/files/math3.gno b/gnovm/tests/files/math3.gno index 592af0aa89d..a0ed2e1aa1e 100644 --- a/gnovm/tests/files/math3.gno +++ b/gnovm/tests/files/math3.gno @@ -1,32 +1,27 @@ package main import ( - "crypto/md5" + "crypto/sha256" "fmt" ) -func md5Crypt(password, salt, magic []byte) []byte { - d := md5.New() - d.Write(password) - d.Write(magic) - d.Write(salt) +func sha256Crypt(password, salt, magic string) []byte { + toHash := password + magic + salt + mixin := sha256.Sum256([]byte(password + salt)) - d2 := md5.New() - d2.Write(password) - d2.Write(salt) - - for i, mixin := 0, d2.Sum(nil); i < len(password); i++ { - d.Write([]byte{mixin[i%16]}) + for i := 0; i < len(password); i++ { + toHash += string(mixin[i%32]) } - return ([]byte)(d.Sum(nil)) // gonative{[]byte} -> []byte + res := sha256.Sum256([]byte(toHash)) + return res[:] } func main() { - b := md5Crypt([]byte("1"), []byte("2"), []byte("3")) + b := sha256Crypt("1", "2", "3") fmt.Println(b) } // Output: -// [187 141 73 89 101 229 33 106 226 63 117 234 117 149 230 21] +// [172 65 148 29 23 72 77 86 46 80 184 188 192 158 154 11 145 11 197 253 206 210 141 253 188 27 157 126 89 142 179 143] diff --git a/gnovm/tests/files/math_native.gno b/gnovm/tests/files/math5.gno similarity index 100% rename from gnovm/tests/files/math_native.gno rename to gnovm/tests/files/math5.gno diff --git a/gnovm/tests/files/method16b.gno b/gnovm/tests/files/method16b.gno index 421a9f44e7b..4f36f48aa37 100644 --- a/gnovm/tests/files/method16b.gno +++ b/gnovm/tests/files/method16b.gno @@ -9,7 +9,7 @@ type Cheese struct { } func (t *Cheese) Hello(param string) { - fmt.Printf("%+v %+v", t, param) + fmt.Printf("%+v %+v\n", t, param) } func main() { diff --git a/gnovm/tests/files/method18.gno b/gnovm/tests/files/method18.gno deleted file mode 100644 index 3da9580dc02..00000000000 --- a/gnovm/tests/files/method18.gno +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "compress/gzip" - "fmt" - - "github.com/gnolang/gno/_test/net/http" -) - -type GzipResponseWriter struct { - http.ResponseWriter - index int - gw *gzip.Writer -} - -type GzipResponseWriterWithCloseNotify struct { - *GzipResponseWriter -} - -func (w GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool { - return w.ResponseWriter.(http.CloseNotifier).CloseNotify() -} - -func main() { - fmt.Println("hello") -} - -// Output: -// hello diff --git a/gnovm/tests/files/method20.gno b/gnovm/tests/files/method20.gno index 7561451b699..7f3bce4c806 100644 --- a/gnovm/tests/files/method20.gno +++ b/gnovm/tests/files/method20.gno @@ -2,16 +2,11 @@ package main import ( "fmt" - "sync" ) -type Hello struct { - mu sync.Mutex -} +type Hello struct{} func (h *Hello) Hi() string { - h.mu.Lock() - h.mu.Unlock() return "hi" } diff --git a/gnovm/tests/files/method24.gno b/gnovm/tests/files/method24.gno deleted file mode 100644 index 624f4397b68..00000000000 --- a/gnovm/tests/files/method24.gno +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "fmt" - "sync" -) - -type Pool struct { - P *sync.Pool -} - -func (p Pool) Get() *Buffer { return &Buffer{} } - -func NewPool() Pool { return Pool{} } - -type Buffer struct { - Bs []byte - Pool Pool -} - -var ( - _pool = NewPool() - Get = _pool.Get -) - -func main() { - fmt.Println(_pool) - fmt.Println(Get()) -} - -// Output: -// {} -// &{[] {}} diff --git a/gnovm/tests/files/method25.gno b/gnovm/tests/files/method25.gno deleted file mode 100644 index a9dff18b6fb..00000000000 --- a/gnovm/tests/files/method25.gno +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "fmt" - "sync" -) - -func (p Pool) Get() *Buffer { return &Buffer{} } - -func NewPool() Pool { return Pool{} } - -type Buffer struct { - Bs []byte - Pool Pool -} - -type Pool struct { - P *sync.Pool -} - -var ( - _pool = NewPool() - Get = _pool.Get -) - -func main() { - fmt.Println(_pool) - fmt.Println(Get()) -} - -// Output: -// {} -// &{[] {}} diff --git a/gnovm/tests/files/op0.gno b/gnovm/tests/files/op0.gno index 860f525a3bd..3c599928be6 100644 --- a/gnovm/tests/files/op0.gno +++ b/gnovm/tests/files/op0.gno @@ -7,7 +7,7 @@ func main() { a = 64 b = 64 c = a * b - fmt.Printf("c: %v %T", c, c) + fmt.Printf("c: %v %T\n", c, c) } // Output: diff --git a/gnovm/tests/files/print0.gno b/gnovm/tests/files/print0.gno index 43cdcf19d39..cab6a7943d1 100644 --- a/gnovm/tests/files/print0.gno +++ b/gnovm/tests/files/print0.gno @@ -2,6 +2,7 @@ package main func main() { print("hello") + println() } // Output: diff --git a/gnovm/tests/files/sample.plugin b/gnovm/tests/files/sample.plugin deleted file mode 100644 index cbe637b73af..00000000000 --- a/gnovm/tests/files/sample.plugin +++ /dev/null @@ -1,19 +0,0 @@ -package sample - -import ( - "fmt" - "net/http" -) - -type Sample struct{} - -func (s *Sample) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - r.Header.Set("X-sample-test", "Hello") - if next != nil { - next(w, r) - } -} - -func Test() { - fmt.Println("Hello from toto.Test()") -} diff --git a/gnovm/tests/files/secure.gi b/gnovm/tests/files/secure.gi deleted file mode 100644 index 3ac731a85ff..00000000000 --- a/gnovm/tests/files/secure.gi +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/unrolled/secure" // or "gopkg.in/unrolled/secure.v1" -) - -var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("hello world")) -}) - -func main() { - secureMiddleware := secure.New(secure.Options{ - AllowedHosts: []string{"example.com", "ssl.example.com"}, - HostsProxyHeaders: []string{"X-Forwarded-Host"}, - SSLRedirect: true, - SSLHost: "ssl.example.com", - SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"}, - STSSeconds: 315360000, - STSIncludeSubdomains: true, - STSPreload: true, - FrameDeny: true, - ContentTypeNosniff: true, - BrowserXssFilter: true, - ContentSecurityPolicy: "script-src $NONCE", - PublicKey: `pin-sha256="base64+primary=="; pin-sha256="base64+backup=="; max-age=5184000; includeSubdomains; report-uri="https://www.example.com/hpkp-report"`, - IsDevelopment: false, - }) - - app := secureMiddleware.Handler(myHandler) - http.ListenAndServe("127.0.0.1:3000", app) -} diff --git a/gnovm/tests/files/std0_stdlibs.gno b/gnovm/tests/files/std0.gno similarity index 100% rename from gnovm/tests/files/std0_stdlibs.gno rename to gnovm/tests/files/std0.gno diff --git a/gnovm/tests/files/std10_stdlibs.gno b/gnovm/tests/files/std10.gno similarity index 100% rename from gnovm/tests/files/std10_stdlibs.gno rename to gnovm/tests/files/std10.gno diff --git a/gnovm/tests/files/std11_stdlibs.gno b/gnovm/tests/files/std11.gno similarity index 100% rename from gnovm/tests/files/std11_stdlibs.gno rename to gnovm/tests/files/std11.gno diff --git a/gnovm/tests/files/std2_stdlibs.gno b/gnovm/tests/files/std2.gno similarity index 100% rename from gnovm/tests/files/std2_stdlibs.gno rename to gnovm/tests/files/std2.gno diff --git a/gnovm/tests/files/std3_stdlibs.gno b/gnovm/tests/files/std3.gno similarity index 100% rename from gnovm/tests/files/std3_stdlibs.gno rename to gnovm/tests/files/std3.gno diff --git a/gnovm/tests/files/std4_stdlibs.gno b/gnovm/tests/files/std4.gno similarity index 100% rename from gnovm/tests/files/std4_stdlibs.gno rename to gnovm/tests/files/std4.gno diff --git a/gnovm/tests/files/std5_stdlibs.gno b/gnovm/tests/files/std5.gno similarity index 90% rename from gnovm/tests/files/std5_stdlibs.gno rename to gnovm/tests/files/std5.gno index 4afa09da8d3..54cfb7846ab 100644 --- a/gnovm/tests/files/std5_stdlibs.gno +++ b/gnovm/tests/files/std5.gno @@ -18,7 +18,7 @@ func main() { // std.GetCallerAt(2) // std/native.gno:44 // main() -// main/files/std5_stdlibs.gno:10 +// main/files/std5.gno:10 // Error: // frame not found diff --git a/gnovm/tests/files/std6_stdlibs.gno b/gnovm/tests/files/std6.gno similarity index 100% rename from gnovm/tests/files/std6_stdlibs.gno rename to gnovm/tests/files/std6.gno diff --git a/gnovm/tests/files/std7_stdlibs.gno b/gnovm/tests/files/std7.gno similarity index 100% rename from gnovm/tests/files/std7_stdlibs.gno rename to gnovm/tests/files/std7.gno diff --git a/gnovm/tests/files/std8_stdlibs.gno b/gnovm/tests/files/std8.gno similarity index 89% rename from gnovm/tests/files/std8_stdlibs.gno rename to gnovm/tests/files/std8.gno index ab5e15bd618..27545f267ce 100644 --- a/gnovm/tests/files/std8_stdlibs.gno +++ b/gnovm/tests/files/std8.gno @@ -28,11 +28,11 @@ func main() { // std.GetCallerAt(4) // std/native.gno:44 // fn() -// main/files/std8_stdlibs.gno:16 +// main/files/std8.gno:16 // testutils.WrapCall(inner) // gno.land/p/demo/testutils/misc.gno:5 // main() -// main/files/std8_stdlibs.gno:21 +// main/files/std8.gno:21 // Error: // frame not found diff --git a/gnovm/tests/files/std9_stdlibs.gno b/gnovm/tests/files/std9.gno similarity index 100% rename from gnovm/tests/files/std9_stdlibs.gno rename to gnovm/tests/files/std9.gno diff --git a/gnovm/tests/files/stdbanker_stdlibs.gno b/gnovm/tests/files/stdbanker.gno similarity index 100% rename from gnovm/tests/files/stdbanker_stdlibs.gno rename to gnovm/tests/files/stdbanker.gno diff --git a/gnovm/tests/files/stdlibs_stdlibs.gno b/gnovm/tests/files/stdlibs.gno similarity index 100% rename from gnovm/tests/files/stdlibs_stdlibs.gno rename to gnovm/tests/files/stdlibs.gno diff --git a/gnovm/tests/files/struct13_stdlibs.gno b/gnovm/tests/files/struct13.gno similarity index 100% rename from gnovm/tests/files/struct13_stdlibs.gno rename to gnovm/tests/files/struct13.gno diff --git a/gnovm/tests/files/struct13_native.gno b/gnovm/tests/files/struct13_native.gno deleted file mode 100644 index 85515555f50..00000000000 --- a/gnovm/tests/files/struct13_native.gno +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/gnolang/gno/_test/net/http" -) - -type Fromage struct { - http.Server -} - -func main() { - a := Fromage{} - fmt.Println(a.Server.WriteTimeout) -} - -// Output: -// 0s diff --git a/gnovm/tests/files/switch21.gno b/gnovm/tests/files/switch21.gno index b13867d4512..5dd70e2a188 100644 --- a/gnovm/tests/files/switch21.gno +++ b/gnovm/tests/files/switch21.gno @@ -6,7 +6,7 @@ func main() { var err error switch v := err.(type) { - case fmt.Formatter: + case interface{ Format() string }: println("formatter") default: fmt.Println(v) diff --git a/gnovm/tests/files/time0_stdlibs.gno b/gnovm/tests/files/time0.gno similarity index 100% rename from gnovm/tests/files/time0_stdlibs.gno rename to gnovm/tests/files/time0.gno diff --git a/gnovm/tests/files/time0_native.gno b/gnovm/tests/files/time0_native.gno deleted file mode 100644 index 52c5b4d6727..00000000000 --- a/gnovm/tests/files/time0_native.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - fmt.Println(time.Now()) -} - -// Output: -// 1970-01-01 00:00:00 +0000 UTC diff --git a/gnovm/tests/files/time1_stdlibs.gno b/gnovm/tests/files/time1.gno similarity index 100% rename from gnovm/tests/files/time1_stdlibs.gno rename to gnovm/tests/files/time1.gno diff --git a/gnovm/tests/files/time11_stdlibs.gno b/gnovm/tests/files/time11.gno similarity index 100% rename from gnovm/tests/files/time11_stdlibs.gno rename to gnovm/tests/files/time11.gno diff --git a/gnovm/tests/files/time11_native.gno b/gnovm/tests/files/time11_native.gno deleted file mode 100644 index 641ab4e6e4d..00000000000 --- a/gnovm/tests/files/time11_native.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -const df = time.Minute * 30 - -func main() { - fmt.Printf("df: %v %T\n", df, df) -} - -// Output: -// df: 30m0s time.Duration diff --git a/gnovm/tests/files/time12_stdlibs.gno b/gnovm/tests/files/time12.gno similarity index 100% rename from gnovm/tests/files/time12_stdlibs.gno rename to gnovm/tests/files/time12.gno diff --git a/gnovm/tests/files/time12_native.gno b/gnovm/tests/files/time12_native.gno deleted file mode 100644 index 890e49cd1f0..00000000000 --- a/gnovm/tests/files/time12_native.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -var twentyFourHours = time.Duration(24 * time.Hour) - -func main() { - fmt.Println(twentyFourHours.Hours()) -} - -// Output: -// 24 diff --git a/gnovm/tests/files/time13_stdlibs.gno b/gnovm/tests/files/time13.gno similarity index 100% rename from gnovm/tests/files/time13_stdlibs.gno rename to gnovm/tests/files/time13.gno diff --git a/gnovm/tests/files/time13_native.gno b/gnovm/tests/files/time13_native.gno deleted file mode 100644 index a2eedafe880..00000000000 --- a/gnovm/tests/files/time13_native.gno +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -var dummy = 1 - -var t time.Time = time.Date(2007, time.November, 10, 23, 4, 5, 0, time.UTC) - -func main() { - t = time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC) - fmt.Println(t.Clock()) -} - -// Output: -// 23 4 5 diff --git a/gnovm/tests/files/time14_stdlibs.gno b/gnovm/tests/files/time14.gno similarity index 100% rename from gnovm/tests/files/time14_stdlibs.gno rename to gnovm/tests/files/time14.gno diff --git a/gnovm/tests/files/time14_native.gno b/gnovm/tests/files/time14_native.gno deleted file mode 100644 index 9f28c57d006..00000000000 --- a/gnovm/tests/files/time14_native.gno +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -var t time.Time - -func f() time.Time { - time := t - return time -} - -func main() { - fmt.Println(f()) -} - -// Output: -// 0001-01-01 00:00:00 +0000 UTC diff --git a/gnovm/tests/files/time16_native.gno b/gnovm/tests/files/time16_native.gno deleted file mode 100644 index 4010667b41c..00000000000 --- a/gnovm/tests/files/time16_native.gno +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - var a int64 = 2 - fmt.Println(time.Second * a) -} - -// Error: -// main/files/time16_native.gno:10:14: incompatible operands in binary expression: go:time.Duration MUL int64 diff --git a/gnovm/tests/files/time17_native.gno b/gnovm/tests/files/time17_native.gno deleted file mode 100644 index 6733c1381cb..00000000000 --- a/gnovm/tests/files/time17_native.gno +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - now := time.Now() - now.In(nil) -} - -// Error: -// time: missing Location in call to Time.In - -// Stacktrace: -// now.In(gonative{*time.Location}) -// gofunction:func(*time.Location) time.Time -// main() -// main/files/time17_native.gno:10 diff --git a/gnovm/tests/files/time1_native.gno b/gnovm/tests/files/time1_native.gno deleted file mode 100644 index 9749d472e08..00000000000 --- a/gnovm/tests/files/time1_native.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - t := time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC) - m := t.Minute() - fmt.Println(t, m) -} - -// Output: -// 2009-11-10 23:04:05 +0000 UTC 4 diff --git a/gnovm/tests/files/time2_stdlibs.gno b/gnovm/tests/files/time2.gno similarity index 100% rename from gnovm/tests/files/time2_stdlibs.gno rename to gnovm/tests/files/time2.gno diff --git a/gnovm/tests/files/time2_native.gno b/gnovm/tests/files/time2_native.gno deleted file mode 100644 index 03ea3a2be96..00000000000 --- a/gnovm/tests/files/time2_native.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - t := time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC) - h, m, s := t.Clock() - fmt.Println(h, m, s) -} - -// Output: -// 23 4 5 diff --git a/gnovm/tests/files/time3_stdlibs.gno b/gnovm/tests/files/time3.gno similarity index 100% rename from gnovm/tests/files/time3_stdlibs.gno rename to gnovm/tests/files/time3.gno diff --git a/gnovm/tests/files/time3_native.gno b/gnovm/tests/files/time3_native.gno deleted file mode 100644 index 0848abd9a13..00000000000 --- a/gnovm/tests/files/time3_native.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -// FIXME related to named returns -func main() { - t := time.Date(2009, time.November, 10, 23, 4, 5, 0, time.UTC) - fmt.Println(t.Clock()) -} - -// Output: -// 23 4 5 diff --git a/gnovm/tests/files/time4_stdlibs.gno b/gnovm/tests/files/time4.gno similarity index 100% rename from gnovm/tests/files/time4_stdlibs.gno rename to gnovm/tests/files/time4.gno diff --git a/gnovm/tests/files/time4_native.gno b/gnovm/tests/files/time4_native.gno deleted file mode 100644 index 3662e35cb01..00000000000 --- a/gnovm/tests/files/time4_native.gno +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - var m time.Month - m = 9 - fmt.Println(m) -} - -// Output: -// September diff --git a/gnovm/tests/files/time6_stdlibs.gno b/gnovm/tests/files/time6.gno similarity index 100% rename from gnovm/tests/files/time6_stdlibs.gno rename to gnovm/tests/files/time6.gno diff --git a/gnovm/tests/files/time6_native.gno b/gnovm/tests/files/time6_native.gno deleted file mode 100644 index c88d3ab8115..00000000000 --- a/gnovm/tests/files/time6_native.gno +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - t := &time.Time{} - t.UnmarshalText([]byte("1985-04-12T23:20:50.52Z")) - - fmt.Println(t) -} - -// Output: -// 1985-04-12 23:20:50.52 +0000 UTC diff --git a/gnovm/tests/files/time7_stdlibs.gno b/gnovm/tests/files/time7.gno similarity index 100% rename from gnovm/tests/files/time7_stdlibs.gno rename to gnovm/tests/files/time7.gno diff --git a/gnovm/tests/files/time7_native.gno b/gnovm/tests/files/time7_native.gno deleted file mode 100644 index 1e02defc80d..00000000000 --- a/gnovm/tests/files/time7_native.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -var d = 2 * time.Second - -func main() { fmt.Println(d) } - -// Output: -// 2s diff --git a/gnovm/tests/files/time9_stdlibs.gno b/gnovm/tests/files/time9.gno similarity index 100% rename from gnovm/tests/files/time9_stdlibs.gno rename to gnovm/tests/files/time9.gno diff --git a/gnovm/tests/files/time9_native.gno b/gnovm/tests/files/time9_native.gno deleted file mode 100644 index a87b4560d1a..00000000000 --- a/gnovm/tests/files/time9_native.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - fmt.Println((5 * time.Minute).Seconds()) -} - -// Output: -// 300 diff --git a/gnovm/tests/files/type11.gno b/gnovm/tests/files/type11.gno index a95be962a59..28aaee838dc 100644 --- a/gnovm/tests/files/type11.gno +++ b/gnovm/tests/files/type11.gno @@ -1,16 +1,17 @@ package main import ( - "compress/gzip" "fmt" - "sync" + "time" ) -var gzipWriterPools [gzip.BestCompression - gzip.BestSpeed + 2]*sync.Pool +const i1 = int(time.Nanosecond) + +var weirdArray [i1 + len("123456789")]time.Duration func main() { - fmt.Printf("%T\n", gzipWriterPools) + fmt.Printf("%T\n", weirdArray) } // Output: -// [10]*sync.Pool +// [10]int64 diff --git a/gnovm/tests/files/type2_stdlibs.gno b/gnovm/tests/files/type2.gno similarity index 100% rename from gnovm/tests/files/type2_stdlibs.gno rename to gnovm/tests/files/type2.gno diff --git a/gnovm/tests/files/type2_native.gno b/gnovm/tests/files/type2_native.gno deleted file mode 100644 index 453fd4b64e7..00000000000 --- a/gnovm/tests/files/type2_native.gno +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -type Options struct { - debug bool -} - -type T1 struct { - opt Options - time time.Time -} - -func main() { - t := T1{} - t.time = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) - fmt.Println(t.time) -} - -// Output: -// 2009-11-10 23:00:00 +0000 UTC diff --git a/gnovm/tests/files/typeassert7_native.gno b/gnovm/tests/files/typeassert7.gno similarity index 100% rename from gnovm/tests/files/typeassert7_native.gno rename to gnovm/tests/files/typeassert7.gno diff --git a/gnovm/tests/files/typeassert7a_native.gno b/gnovm/tests/files/typeassert7a.gno similarity index 87% rename from gnovm/tests/files/typeassert7a_native.gno rename to gnovm/tests/files/typeassert7a.gno index cafb27b6a6b..6e0aa0e8dca 100644 --- a/gnovm/tests/files/typeassert7a_native.gno +++ b/gnovm/tests/files/typeassert7a.gno @@ -39,5 +39,5 @@ func main() { // Output: // ok -// interface conversion: interface is nil, not gonative{io.Reader} +// interface conversion: interface is nil, not io.Reader // ok diff --git a/gnovm/tests/files/types/add_assign_f0_stdlibs.gno b/gnovm/tests/files/types/add_assign_f0.gno similarity index 71% rename from gnovm/tests/files/types/add_assign_f0_stdlibs.gno rename to gnovm/tests/files/types/add_assign_f0.gno index 67c6777d085..a3df217aa7d 100644 --- a/gnovm/tests/files/types/add_assign_f0_stdlibs.gno +++ b/gnovm/tests/files/types/add_assign_f0.gno @@ -22,4 +22,4 @@ func main() { } // Error: -// main/files/types/add_assign_f0_stdlibs.gno:20:2: invalid operation: mismatched types int and .uverse.error +// main/files/types/add_assign_f0.gno:20:2: invalid operation: mismatched types int and .uverse.error diff --git a/gnovm/tests/files/types/add_assign_f1_stdlibs.gno b/gnovm/tests/files/types/add_assign_f1.gno similarity index 81% rename from gnovm/tests/files/types/add_assign_f1_stdlibs.gno rename to gnovm/tests/files/types/add_assign_f1.gno index d83a66359c9..195d8ab1c1c 100644 --- a/gnovm/tests/files/types/add_assign_f1_stdlibs.gno +++ b/gnovm/tests/files/types/add_assign_f1.gno @@ -25,4 +25,4 @@ func main() { } // Error: -// main/files/types/add_assign_f1_stdlibs.gno:21:2: invalid operation: mismatched types main.Error and .uverse.error +// main/files/types/add_assign_f1.gno:21:2: invalid operation: mismatched types main.Error and .uverse.error diff --git a/gnovm/tests/files/types/add_assign_f2_stdlibs.gno b/gnovm/tests/files/types/add_assign_f2.gno similarity index 75% rename from gnovm/tests/files/types/add_assign_f2_stdlibs.gno rename to gnovm/tests/files/types/add_assign_f2.gno index 8be6b3cfb7b..2603ee273d6 100644 --- a/gnovm/tests/files/types/add_assign_f2_stdlibs.gno +++ b/gnovm/tests/files/types/add_assign_f2.gno @@ -22,4 +22,4 @@ func main() { } // Error: -// main/files/types/add_assign_f2_stdlibs.gno:20:2: operator += not defined on: InterfaceKind +// main/files/types/add_assign_f2.gno:20:2: operator += not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_f0_stdlibs.gno b/gnovm/tests/files/types/add_f0.gno similarity index 74% rename from gnovm/tests/files/types/add_f0_stdlibs.gno rename to gnovm/tests/files/types/add_f0.gno index 33e0346d44f..4497efd41f1 100644 --- a/gnovm/tests/files/types/add_f0_stdlibs.gno +++ b/gnovm/tests/files/types/add_f0.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/types/add_f0_stdlibs.gno:19:10: operator + not defined on: InterfaceKind +// main/files/types/add_f0.gno:19:10: operator + not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/add_f1_stdlibs.gno b/gnovm/tests/files/types/add_f1.gno similarity index 75% rename from gnovm/tests/files/types/add_f1_stdlibs.gno rename to gnovm/tests/files/types/add_f1.gno index e46d67e93d7..0c403aff6a4 100644 --- a/gnovm/tests/files/types/add_f1_stdlibs.gno +++ b/gnovm/tests/files/types/add_f1.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/types/add_f1_stdlibs.gno:19:10: operator + not defined on: InterfaceKind +// main/files/types/add_f1.gno:19:10: operator + not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/and_f0_stdlibs.gno b/gnovm/tests/files/types/and_f0.gno similarity index 74% rename from gnovm/tests/files/types/and_f0_stdlibs.gno rename to gnovm/tests/files/types/and_f0.gno index e80f69332a8..2c82610b932 100644 --- a/gnovm/tests/files/types/and_f0_stdlibs.gno +++ b/gnovm/tests/files/types/and_f0.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/types/and_f0_stdlibs.gno:19:10: operator & not defined on: InterfaceKind +// main/files/types/and_f0.gno:19:10: operator & not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/and_f1_stdlibs.gno b/gnovm/tests/files/types/and_f1.gno similarity index 75% rename from gnovm/tests/files/types/and_f1_stdlibs.gno rename to gnovm/tests/files/types/and_f1.gno index 42a6aa4b466..41a72899ee2 100644 --- a/gnovm/tests/files/types/and_f1_stdlibs.gno +++ b/gnovm/tests/files/types/and_f1.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/types/and_f1_stdlibs.gno:19:10: operator & not defined on: InterfaceKind +// main/files/types/and_f1.gno:19:10: operator & not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/cmp_iface_0_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_0.gno similarity index 100% rename from gnovm/tests/files/types/cmp_iface_0_stdlibs.gno rename to gnovm/tests/files/types/cmp_iface_0.gno diff --git a/gnovm/tests/files/types/cmp_iface_3_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_3.gno similarity index 100% rename from gnovm/tests/files/types/cmp_iface_3_stdlibs.gno rename to gnovm/tests/files/types/cmp_iface_3.gno diff --git a/gnovm/tests/files/types/eql_0f8_stdlibs.gno b/gnovm/tests/files/types/cmp_iface_5.gno similarity index 75% rename from gnovm/tests/files/types/eql_0f8_stdlibs.gno rename to gnovm/tests/files/types/cmp_iface_5.gno index a6e24110432..7d748bacef3 100644 --- a/gnovm/tests/files/types/eql_0f8_stdlibs.gno +++ b/gnovm/tests/files/types/cmp_iface_5.gno @@ -24,4 +24,4 @@ func main() { } // Error: -// main/files/types/eql_0f8_stdlibs.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/files/types/cmp_iface_5.gno:19:5: int64 does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/eql_0b4_native.gno b/gnovm/tests/files/types/eql_0b4.gno similarity index 50% rename from gnovm/tests/files/types/eql_0b4_native.gno rename to gnovm/tests/files/types/eql_0b4.gno index 7c7baf01924..14a719c41d0 100644 --- a/gnovm/tests/files/types/eql_0b4_native.gno +++ b/gnovm/tests/files/types/eql_0b4.gno @@ -10,4 +10,4 @@ func main() { } // Error: -// main/files/types/eql_0b4_native.gno:9:10: unexpected type pair: cannot use bigint as gonative{error} +// main/files/types/eql_0b4.gno:9:10: bigint does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/eql_0b4_stdlibs.gno b/gnovm/tests/files/types/eql_0b4_stdlibs.gno deleted file mode 100644 index eac923c6d31..00000000000 --- a/gnovm/tests/files/types/eql_0b4_stdlibs.gno +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import ( - "errors" -) - -func main() { - errCmp := errors.New("xxx") - println(5 == errCmp) -} - -// Error: -// main/files/types/eql_0b4_stdlibs.gno:9:10: bigint does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/eql_0f0_native.gno b/gnovm/tests/files/types/eql_0f0.gno similarity index 75% rename from gnovm/tests/files/types/eql_0f0_native.gno rename to gnovm/tests/files/types/eql_0f0.gno index e32325f5cf6..f609c0b5ced 100644 --- a/gnovm/tests/files/types/eql_0f0_native.gno +++ b/gnovm/tests/files/types/eql_0f0.gno @@ -25,4 +25,4 @@ func main() { } // Error: -// main/files/types/eql_0f0_native.gno:19:5: unexpected type pair: cannot use bigint as gonative{error} +// main/files/types/eql_0f0.gno:19:5: bigint does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/eql_0f0_stdlibs.gno b/gnovm/tests/files/types/eql_0f0_stdlibs.gno deleted file mode 100644 index 4947627cba4..00000000000 --- a/gnovm/tests/files/types/eql_0f0_stdlibs.gno +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -var errCmp = errors.New("XXXX") - -// special case: -// one is interface -func main() { - if 1 == errCmp { - //if errCmp == 1 { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Error: -// main/files/types/eql_0f0_stdlibs.gno:19:5: bigint does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/eql_0f1_stdlibs.gno b/gnovm/tests/files/types/eql_0f1.gno similarity index 76% rename from gnovm/tests/files/types/eql_0f1_stdlibs.gno rename to gnovm/tests/files/types/eql_0f1.gno index cab7fcfab33..fd40dfcd29b 100644 --- a/gnovm/tests/files/types/eql_0f1_stdlibs.gno +++ b/gnovm/tests/files/types/eql_0f1.gno @@ -25,4 +25,4 @@ func main() { } // Error: -// main/files/types/eql_0f1_stdlibs.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/files/types/eql_0f1.gno:19:5: int64 does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/eql_0f27_stdlibs.gno b/gnovm/tests/files/types/eql_0f27.gno similarity index 75% rename from gnovm/tests/files/types/eql_0f27_stdlibs.gno rename to gnovm/tests/files/types/eql_0f27.gno index 188153aeb51..e90bbab9ca5 100644 --- a/gnovm/tests/files/types/eql_0f27_stdlibs.gno +++ b/gnovm/tests/files/types/eql_0f27.gno @@ -18,4 +18,4 @@ func main() { } // Error: -// main/files/types/eql_0f27_stdlibs.gno:13:5: operator > not defined on: InterfaceKind +// main/files/types/eql_0f27.gno:13:5: operator > not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2b_native.gno b/gnovm/tests/files/types/eql_0f2b.gno similarity index 80% rename from gnovm/tests/files/types/eql_0f2b_native.gno rename to gnovm/tests/files/types/eql_0f2b.gno index 9de6155c5be..14a94dfde9a 100644 --- a/gnovm/tests/files/types/eql_0f2b_native.gno +++ b/gnovm/tests/files/types/eql_0f2b.gno @@ -25,4 +25,4 @@ func main() { } // Error: -// main/files/types/eql_0f2b_native.gno:19:5: operator <= not defined on: InterfaceKind +// main/files/types/eql_0f2b.gno:19:5: operator <= not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2b_stdlibs.gno b/gnovm/tests/files/types/eql_0f2b_stdlibs.gno deleted file mode 100644 index ac3616d163d..00000000000 --- a/gnovm/tests/files/types/eql_0f2b_stdlibs.gno +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -var errCmp = errors.New("XXXX") - -// special case: -// one is interface -func main() { - if Error(0) <= errCmp { - //if errCmp == 1 { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Error: -// main/files/types/eql_0f2b_stdlibs.gno:19:5: operator <= not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2c_native.gno b/gnovm/tests/files/types/eql_0f2c.gno similarity index 80% rename from gnovm/tests/files/types/eql_0f2c_native.gno rename to gnovm/tests/files/types/eql_0f2c.gno index edd5ac3f23a..3374357a145 100644 --- a/gnovm/tests/files/types/eql_0f2c_native.gno +++ b/gnovm/tests/files/types/eql_0f2c.gno @@ -25,4 +25,4 @@ func main() { } // Error: -// main/files/types/eql_0f2c_native.gno:19:5: operator < not defined on: InterfaceKind +// main/files/types/eql_0f2c.gno:19:5: operator < not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f2c_stdlibs.gno b/gnovm/tests/files/types/eql_0f2c_stdlibs.gno deleted file mode 100644 index 3a6ac3395b6..00000000000 --- a/gnovm/tests/files/types/eql_0f2c_stdlibs.gno +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "errors" - "strconv" -) - -type Error int64 - -func (e Error) Error() string { - return "error: " + strconv.Itoa(int(e)) -} - -var errCmp = errors.New("XXXX") - -// special case: -// one is interface -func main() { - if Error(0) < errCmp { - //if errCmp == 1 { - println("what the firetruck?") - } else { - println("something else") - } -} - -// Error: -// main/files/types/eql_0f2c_stdlibs.gno:19:5: operator < not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/eql_0f40_stdlibs.gno b/gnovm/tests/files/types/eql_0f40.gno similarity index 100% rename from gnovm/tests/files/types/eql_0f40_stdlibs.gno rename to gnovm/tests/files/types/eql_0f40.gno diff --git a/gnovm/tests/files/types/eql_0f41_stdlibs.gno b/gnovm/tests/files/types/eql_0f41.gno similarity index 77% rename from gnovm/tests/files/types/eql_0f41_stdlibs.gno rename to gnovm/tests/files/types/eql_0f41.gno index be78ea6ed79..162586e2977 100644 --- a/gnovm/tests/files/types/eql_0f41_stdlibs.gno +++ b/gnovm/tests/files/types/eql_0f41.gno @@ -32,4 +32,4 @@ func main() { } // Error: -// main/files/types/eql_0f41_stdlibs.gno:27:5: main.animal does not implement .uverse.error (missing method Error) +// main/files/types/eql_0f41.gno:27:5: main.animal does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno b/gnovm/tests/files/types/eql_0f8.gno similarity index 75% rename from gnovm/tests/files/types/cmp_iface_5_stdlibs.gno rename to gnovm/tests/files/types/eql_0f8.gno index e706c74808e..17bb5f9002d 100644 --- a/gnovm/tests/files/types/cmp_iface_5_stdlibs.gno +++ b/gnovm/tests/files/types/eql_0f8.gno @@ -24,4 +24,4 @@ func main() { } // Error: -// main/files/types/cmp_iface_5_stdlibs.gno:19:5: int64 does not implement .uverse.error (missing method Error) +// main/files/types/eql_0f8.gno:19:5: int64 does not implement .uverse.error (missing method Error) diff --git a/gnovm/tests/files/types/explicit_conversion_0.gno b/gnovm/tests/files/types/explicit_conversion_0.gno index ac5e8c2eb94..be7800590e5 100644 --- a/gnovm/tests/files/types/explicit_conversion_0.gno +++ b/gnovm/tests/files/types/explicit_conversion_0.gno @@ -5,7 +5,7 @@ import "fmt" func main() { r := int(uint(1)) println(r) - fmt.Printf("%T \n", r) + fmt.Printf("%T\n", r) } // Output: diff --git a/gnovm/tests/files/types/explicit_conversion_1.gno b/gnovm/tests/files/types/explicit_conversion_1.gno index 60fc7b95b64..472a430fdc5 100644 --- a/gnovm/tests/files/types/explicit_conversion_1.gno +++ b/gnovm/tests/files/types/explicit_conversion_1.gno @@ -6,7 +6,7 @@ import "fmt" func main() { r := int(uint(string("hello"))) println(r) - fmt.Printf("%T \n", r) + fmt.Printf("%T\n", r) } // Error: diff --git a/gnovm/tests/files/types/explicit_conversion_2.gno b/gnovm/tests/files/types/explicit_conversion_2.gno index f932a970a9a..30da1d31154 100644 --- a/gnovm/tests/files/types/explicit_conversion_2.gno +++ b/gnovm/tests/files/types/explicit_conversion_2.gno @@ -6,7 +6,7 @@ func main() { x := 1 r := uint(+x) println(r) - fmt.Printf("%T \n", r) + fmt.Printf("%T\n", r) } // Output: diff --git a/gnovm/tests/files/types/or_f0_stdlibs.gno b/gnovm/tests/files/types/or_f0.gno similarity index 75% rename from gnovm/tests/files/types/or_f0_stdlibs.gno rename to gnovm/tests/files/types/or_f0.gno index 8e6fb54772a..34ffdaa87fe 100644 --- a/gnovm/tests/files/types/or_f0_stdlibs.gno +++ b/gnovm/tests/files/types/or_f0.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/types/or_f0_stdlibs.gno:19:10: operator | not defined on: InterfaceKind +// main/files/types/or_f0.gno:19:10: operator | not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/or_f1_stdlibs.gno b/gnovm/tests/files/types/or_f1.gno similarity index 75% rename from gnovm/tests/files/types/or_f1_stdlibs.gno rename to gnovm/tests/files/types/or_f1.gno index 5013126c9fa..96a68632320 100644 --- a/gnovm/tests/files/types/or_f1_stdlibs.gno +++ b/gnovm/tests/files/types/or_f1.gno @@ -20,4 +20,4 @@ func main() { } // Error: -// main/files/types/or_f1_stdlibs.gno:19:10: operator | not defined on: InterfaceKind +// main/files/types/or_f1.gno:19:10: operator | not defined on: InterfaceKind diff --git a/gnovm/tests/files/types/shift_b0.gno b/gnovm/tests/files/types/shift_b0.gno index fa9ee4ed2a0..9717f04a56d 100644 --- a/gnovm/tests/files/types/shift_b0.gno +++ b/gnovm/tests/files/types/shift_b0.gno @@ -6,7 +6,7 @@ func main() { x := 2 r := uint64(1 << x) println(r) - fmt.Printf("%T \n", r) + fmt.Printf("%T\n", r) } // Output: diff --git a/gnovm/tests/files/types/shift_b1.gno b/gnovm/tests/files/types/shift_b1.gno index 403887269c0..8f2615ba93d 100644 --- a/gnovm/tests/files/types/shift_b1.gno +++ b/gnovm/tests/files/types/shift_b1.gno @@ -6,7 +6,7 @@ func main() { x := 2 r := uint64(1<.Panic() -// gno.land/r/test/main.gno:7 +// gno.land/r/test/files/zrealm_panic.gno:7 // main() -// gno.land/r/test/main.gno:12 +// gno.land/r/test/files/zrealm_panic.gno:12 diff --git a/gnovm/tests/files/zrealm_std0_stdlibs.gno b/gnovm/tests/files/zrealm_std0.gno similarity index 100% rename from gnovm/tests/files/zrealm_std0_stdlibs.gno rename to gnovm/tests/files/zrealm_std0.gno diff --git a/gnovm/tests/files/zrealm_std1_stdlibs.gno b/gnovm/tests/files/zrealm_std1.gno similarity index 100% rename from gnovm/tests/files/zrealm_std1_stdlibs.gno rename to gnovm/tests/files/zrealm_std1.gno diff --git a/gnovm/tests/files/zrealm_std2_stdlibs.gno b/gnovm/tests/files/zrealm_std2.gno similarity index 100% rename from gnovm/tests/files/zrealm_std2_stdlibs.gno rename to gnovm/tests/files/zrealm_std2.gno diff --git a/gnovm/tests/files/zrealm_std3_stdlibs.gno b/gnovm/tests/files/zrealm_std3.gno similarity index 100% rename from gnovm/tests/files/zrealm_std3_stdlibs.gno rename to gnovm/tests/files/zrealm_std3.gno diff --git a/gnovm/tests/files/zrealm_std4_stdlibs.gno b/gnovm/tests/files/zrealm_std4.gno similarity index 100% rename from gnovm/tests/files/zrealm_std4_stdlibs.gno rename to gnovm/tests/files/zrealm_std4.gno diff --git a/gnovm/tests/files/zrealm_std5_stdlibs.gno b/gnovm/tests/files/zrealm_std5.gno similarity index 100% rename from gnovm/tests/files/zrealm_std5_stdlibs.gno rename to gnovm/tests/files/zrealm_std5.gno diff --git a/gnovm/tests/files/zrealm_std6_stdlibs.gno b/gnovm/tests/files/zrealm_std6.gno similarity index 100% rename from gnovm/tests/files/zrealm_std6_stdlibs.gno rename to gnovm/tests/files/zrealm_std6.gno diff --git a/gnovm/tests/files/zrealm_tests0_stdlibs.gno b/gnovm/tests/files/zrealm_tests0.gno similarity index 99% rename from gnovm/tests/files/zrealm_tests0_stdlibs.gno rename to gnovm/tests/files/zrealm_tests0.gno index d11701505e5..82e4d418217 100644 --- a/gnovm/tests/files/zrealm_tests0_stdlibs.gno +++ b/gnovm/tests/files/zrealm_tests0.gno @@ -14,12 +14,15 @@ func init() { func main() { tests_foo.AddFooStringer("three") println(tests.Render("")) + println("end") } // Output: // 0: &FooStringer{one} // 1: &FooStringer{two} // 2: &FooStringer{three} +// +// end // Realm: // switchrealm["gno.land/r/demo/tests"] diff --git a/gnovm/tests/files/zrealm_testutils0_stdlibs.gno b/gnovm/tests/files/zrealm_testutils0.gno similarity index 100% rename from gnovm/tests/files/zrealm_testutils0_stdlibs.gno rename to gnovm/tests/files/zrealm_testutils0.gno diff --git a/gnovm/tests/files/zregexp_stdlibs.gno b/gnovm/tests/files/zregexp.gno similarity index 100% rename from gnovm/tests/files/zregexp_stdlibs.gno rename to gnovm/tests/files/zregexp.gno diff --git a/gnovm/tests/imports.go b/gnovm/tests/imports.go deleted file mode 100644 index 66398ba5f50..00000000000 --- a/gnovm/tests/imports.go +++ /dev/null @@ -1,492 +0,0 @@ -package tests - -import ( - "bufio" - "bytes" - "compress/flate" - "compress/gzip" - "context" - "crypto/md5" //nolint:gosec - crand "crypto/rand" - "crypto/sha1" //nolint:gosec - "encoding/base64" - "encoding/binary" - "encoding/json" - "encoding/xml" - "errors" - "flag" - "fmt" - "hash/fnv" - "image" - "image/color" - "io" - "log" - "math" - "math/big" - "math/rand/v2" - "net" - "net/url" - "os" - "path/filepath" - "reflect" - "strconv" - "strings" - "sync" - "sync/atomic" - "text/template" - "time" - "unicode/utf8" - - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - teststdlibs "github.com/gnolang/gno/gnovm/tests/stdlibs" - teststd "github.com/gnolang/gno/gnovm/tests/stdlibs/std" - "github.com/gnolang/gno/tm2/pkg/db/memdb" - osm "github.com/gnolang/gno/tm2/pkg/os" - "github.com/gnolang/gno/tm2/pkg/std" - "github.com/gnolang/gno/tm2/pkg/store/dbadapter" - "github.com/gnolang/gno/tm2/pkg/store/iavl" - stypes "github.com/gnolang/gno/tm2/pkg/store/types" -) - -type importMode uint64 - -// Import modes to control the import behaviour of TestStore. -const ( - // use stdlibs/* only (except a few exceptions). for stdlibs/* and examples/* testing. - ImportModeStdlibsOnly importMode = iota - // use stdlibs/* if present, otherwise use native. used in files/tests, excluded for *_native.go - ImportModeStdlibsPreferred - // do not use stdlibs/* if native registered. used in files/tests, excluded for *_stdlibs.go - ImportModeNativePreferred -) - -// NOTE: this isn't safe, should only be used for testing. -func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Writer, mode importMode) (resStore gno.Store) { - getPackage := func(pkgPath string, store gno.Store) (pn *gno.PackageNode, pv *gno.PackageValue) { - if pkgPath == "" { - panic(fmt.Sprintf("invalid zero package path in testStore().pkgGetter")) - } - if mode != ImportModeStdlibsOnly && - mode != ImportModeStdlibsPreferred && - mode != ImportModeNativePreferred { - panic(fmt.Sprintf("unrecognized import mode")) - } - - if filesPath != "" { - // if _test package... - const testPath = "github.com/gnolang/gno/_test/" - if strings.HasPrefix(pkgPath, testPath) { - baseDir := filepath.Join(filesPath, "extern", pkgPath[len(testPath):]) - memPkg := gno.ReadMemPackage(baseDir, pkgPath) - send := std.Coins{} - ctx := TestContext(pkgPath, send) - m2 := gno.NewMachineWithOptions(gno.MachineOptions{ - PkgPath: "test", - Output: stdout, - Store: store, - Context: ctx, - }) - // pkg := gno.NewPackageNode(gno.Name(memPkg.Name), memPkg.Path, nil) - // pv := pkg.NewPackage() - // m2.SetActivePackage(pv) - // XXX remove second arg 'false' and remove all gonative stuff. - return m2.RunMemPackage(memPkg, false) - } - } - - // if stdlibs package is preferred , try to load it first. - if mode == ImportModeStdlibsOnly || - mode == ImportModeStdlibsPreferred { - pn, pv = loadStdlib(rootDir, pkgPath, store, stdout) - if pn != nil { - return - } - } - - // if native package is allowed, return it. - if pkgPath == "os" || // special cases even when StdlibsOnly (for tests). - pkgPath == "fmt" || // TODO: try to minimize these exceptions over time. - pkgPath == "log" || - pkgPath == "crypto/rand" || - pkgPath == "crypto/md5" || - pkgPath == "crypto/sha1" || - pkgPath == "encoding/binary" || - pkgPath == "encoding/json" || - pkgPath == "encoding/xml" || - pkgPath == "internal/os_test" || - pkgPath == "math/big" || - mode == ImportModeStdlibsPreferred || - mode == ImportModeNativePreferred { - switch pkgPath { - case "os": - pkg := gno.NewPackageNode("os", pkgPath, nil) - pkg.DefineGoNativeValue("Stdin", stdin) - pkg.DefineGoNativeValue("Stdout", stdout) - pkg.DefineGoNativeValue("Stderr", stderr) - return pkg, pkg.NewPackage() - case "fmt": - pkg := gno.NewPackageNode("fmt", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf((*fmt.Stringer)(nil)).Elem()) - pkg.DefineGoNativeType(reflect.TypeOf((*fmt.Formatter)(nil)).Elem()) - pkg.DefineGoNativeValue("Println", func(a ...interface{}) (n int, err error) { - // NOTE: uncomment to debug long running tests - // fmt.Println(a...) - res := fmt.Sprintln(a...) - return stdout.Write([]byte(res)) - }) - pkg.DefineGoNativeValue("Printf", func(format string, a ...interface{}) (n int, err error) { - res := fmt.Sprintf(format, a...) - return stdout.Write([]byte(res)) - }) - pkg.DefineGoNativeValue("Print", func(a ...interface{}) (n int, err error) { - res := fmt.Sprint(a...) - return stdout.Write([]byte(res)) - }) - pkg.DefineGoNativeValue("Sprint", fmt.Sprint) - pkg.DefineGoNativeValue("Sprintf", fmt.Sprintf) - pkg.DefineGoNativeValue("Sprintln", fmt.Sprintln) - pkg.DefineGoNativeValue("Sscanf", fmt.Sscanf) - pkg.DefineGoNativeValue("Errorf", fmt.Errorf) - pkg.DefineGoNativeValue("Fprintln", fmt.Fprintln) - pkg.DefineGoNativeValue("Fprintf", fmt.Fprintf) - pkg.DefineGoNativeValue("Fprint", fmt.Fprint) - return pkg, pkg.NewPackage() - case "encoding/base64": - pkg := gno.NewPackageNode("base64", pkgPath, nil) - pkg.DefineGoNativeValue("RawStdEncoding", base64.RawStdEncoding) - pkg.DefineGoNativeValue("StdEncoding", base64.StdEncoding) - pkg.DefineGoNativeValue("NewDecoder", base64.NewDecoder) - return pkg, pkg.NewPackage() - case "encoding/binary": - pkg := gno.NewPackageNode("binary", pkgPath, nil) - pkg.DefineGoNativeValue("LittleEndian", binary.LittleEndian) - pkg.DefineGoNativeValue("BigEndian", binary.BigEndian) - pkg.DefineGoNativeValue("Write", binary.BigEndian) // warn: use reflection - return pkg, pkg.NewPackage() - case "encoding/json": - pkg := gno.NewPackageNode("json", pkgPath, nil) - pkg.DefineGoNativeValue("Unmarshal", json.Unmarshal) - pkg.DefineGoNativeValue("Marshal", json.Marshal) - return pkg, pkg.NewPackage() - case "encoding/xml": - pkg := gno.NewPackageNode("xml", pkgPath, nil) - pkg.DefineGoNativeValue("Unmarshal", xml.Unmarshal) - return pkg, pkg.NewPackage() - case "internal/os_test": - pkg := gno.NewPackageNode("os_test", pkgPath, nil) - pkg.DefineNative("Sleep", - gno.Flds( // params - "d", gno.AnyT(), // NOTE: should be time.Duration - ), - gno.Flds( // results - ), - func(m *gno.Machine) { - // For testing purposes here, nanoseconds are separately kept track. - arg0 := m.LastBlock().GetParams1().TV - d := arg0.GetInt64() - sec := d / int64(time.Second) - nano := d % int64(time.Second) - ctx := m.Context.(*teststd.TestExecContext) - ctx.Timestamp += sec - ctx.TimestampNano += nano - if ctx.TimestampNano >= int64(time.Second) { - ctx.Timestamp += 1 - ctx.TimestampNano -= int64(time.Second) - } - m.Context = ctx - }, - ) - return pkg, pkg.NewPackage() - case "net": - pkg := gno.NewPackageNode("net", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(net.TCPAddr{})) - pkg.DefineGoNativeValue("IPv4", net.IPv4) - return pkg, pkg.NewPackage() - case "net/url": - pkg := gno.NewPackageNode("url", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(url.Values{})) - return pkg, pkg.NewPackage() - case "bufio": - pkg := gno.NewPackageNode("bufio", pkgPath, nil) - pkg.DefineGoNativeValue("NewScanner", bufio.NewScanner) - pkg.DefineGoNativeType(reflect.TypeOf(bufio.SplitFunc(nil))) - return pkg, pkg.NewPackage() - case "bytes": - pkg := gno.NewPackageNode("bytes", pkgPath, nil) - pkg.DefineGoNativeValue("Equal", bytes.Equal) - pkg.DefineGoNativeValue("Compare", bytes.Compare) - pkg.DefineGoNativeValue("NewReader", bytes.NewReader) - pkg.DefineGoNativeValue("NewBuffer", bytes.NewBuffer) - pkg.DefineGoNativeValue("Repeat", bytes.Repeat) - pkg.DefineGoNativeType(reflect.TypeOf(bytes.Buffer{})) - return pkg, pkg.NewPackage() - case "time": - pkg := gno.NewPackageNode("time", pkgPath, nil) - pkg.DefineGoNativeConstValue("Millisecond", time.Millisecond) - pkg.DefineGoNativeConstValue("Second", time.Second) - pkg.DefineGoNativeConstValue("Minute", time.Minute) - pkg.DefineGoNativeConstValue("Hour", time.Hour) - pkg.DefineGoNativeConstValue("Date", time.Date) - pkg.DefineGoNativeConstValue("Now", func() time.Time { return time.Unix(0, 0).UTC() }) // deterministic - pkg.DefineGoNativeConstValue("January", time.January) - pkg.DefineGoNativeConstValue("February", time.February) - pkg.DefineGoNativeConstValue("March", time.March) - pkg.DefineGoNativeConstValue("April", time.April) - pkg.DefineGoNativeConstValue("May", time.May) - pkg.DefineGoNativeConstValue("June", time.June) - pkg.DefineGoNativeConstValue("July", time.July) - pkg.DefineGoNativeConstValue("August", time.August) - pkg.DefineGoNativeConstValue("September", time.September) - pkg.DefineGoNativeConstValue("November", time.November) - pkg.DefineGoNativeConstValue("December", time.December) - pkg.DefineGoNativeValue("UTC", time.UTC) - pkg.DefineGoNativeValue("Unix", time.Unix) - pkg.DefineGoNativeType(reflect.TypeOf(time.Time{})) - pkg.DefineGoNativeType(reflect.TypeOf(time.Duration(0))) - pkg.DefineGoNativeType(reflect.TypeOf(time.Month(0))) - pkg.DefineGoNativeValue("LoadLocation", time.LoadLocation) - return pkg, pkg.NewPackage() - case "strconv": - pkg := gno.NewPackageNode("strconv", pkgPath, nil) - pkg.DefineGoNativeValue("Itoa", strconv.Itoa) - pkg.DefineGoNativeValue("Atoi", strconv.Atoi) - pkg.DefineGoNativeValue("ParseInt", strconv.ParseInt) - pkg.DefineGoNativeValue("Quote", strconv.Quote) - pkg.DefineGoNativeValue("FormatUint", strconv.FormatUint) - pkg.DefineGoNativeType(reflect.TypeOf(strconv.NumError{})) - return pkg, pkg.NewPackage() - case "strings": - pkg := gno.NewPackageNode("strings", pkgPath, nil) - pkg.DefineGoNativeValue("Split", strings.Split) - pkg.DefineGoNativeValue("SplitN", strings.SplitN) - pkg.DefineGoNativeValue("Contains", strings.Contains) - pkg.DefineGoNativeValue("TrimSpace", strings.TrimSpace) - pkg.DefineGoNativeValue("HasPrefix", strings.HasPrefix) - pkg.DefineGoNativeValue("NewReader", strings.NewReader) - pkg.DefineGoNativeValue("Index", strings.Index) - pkg.DefineGoNativeValue("IndexRune", strings.IndexRune) - pkg.DefineGoNativeValue("Join", strings.Join) - pkg.DefineGoNativeType(reflect.TypeOf(strings.Builder{})) - return pkg, pkg.NewPackage() - case "math": - pkg := gno.NewPackageNode("math", pkgPath, nil) - pkg.DefineGoNativeValue("Abs", math.Abs) - pkg.DefineGoNativeValue("Cos", math.Cos) - pkg.DefineGoNativeConstValue("Pi", math.Pi) - pkg.DefineGoNativeValue("Float64bits", math.Float64bits) - pkg.DefineGoNativeConstValue("MaxFloat32", math.MaxFloat32) - pkg.DefineGoNativeConstValue("MaxFloat64", math.MaxFloat64) - pkg.DefineGoNativeConstValue("MaxUint32", uint32(math.MaxUint32)) - pkg.DefineGoNativeConstValue("MaxUint64", uint64(math.MaxUint64)) - pkg.DefineGoNativeConstValue("MinInt8", math.MinInt8) - pkg.DefineGoNativeConstValue("MinInt16", math.MinInt16) - pkg.DefineGoNativeConstValue("MinInt32", math.MinInt32) - pkg.DefineGoNativeConstValue("MinInt64", int64(math.MinInt64)) - pkg.DefineGoNativeConstValue("MaxInt8", math.MaxInt8) - pkg.DefineGoNativeConstValue("MaxInt16", math.MaxInt16) - pkg.DefineGoNativeConstValue("MaxInt32", math.MaxInt32) - pkg.DefineGoNativeConstValue("MaxInt64", int64(math.MaxInt64)) - return pkg, pkg.NewPackage() - case "math/rand": - // XXX only expose for tests. - pkg := gno.NewPackageNode("rand", pkgPath, nil) - // make native rand same as gno rand. - rnd := rand.New(rand.NewPCG(0, 0)) //nolint:gosec - pkg.DefineGoNativeValue("IntN", rnd.IntN) - pkg.DefineGoNativeValue("Uint32", rnd.Uint32) - return pkg, pkg.NewPackage() - case "crypto/rand": - pkg := gno.NewPackageNode("rand", pkgPath, nil) - pkg.DefineGoNativeValue("Prime", crand.Prime) - // for determinism: - // pkg.DefineGoNativeValue("Reader", crand.Reader) - pkg.DefineGoNativeValue("Reader", &dummyReader{}) - return pkg, pkg.NewPackage() - case "crypto/md5": - pkg := gno.NewPackageNode("md5", pkgPath, nil) - pkg.DefineGoNativeValue("New", md5.New) - return pkg, pkg.NewPackage() - case "crypto/sha1": - pkg := gno.NewPackageNode("sha1", pkgPath, nil) - pkg.DefineGoNativeValue("New", sha1.New) - return pkg, pkg.NewPackage() - case "image": - pkg := gno.NewPackageNode("image", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(image.Point{})) - return pkg, pkg.NewPackage() - case "image/color": - pkg := gno.NewPackageNode("color", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(color.NRGBA64{})) - return pkg, pkg.NewPackage() - case "compress/flate": - pkg := gno.NewPackageNode("flate", pkgPath, nil) - pkg.DefineGoNativeConstValue("BestSpeed", flate.BestSpeed) - return pkg, pkg.NewPackage() - case "compress/gzip": - pkg := gno.NewPackageNode("gzip", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(gzip.Writer{})) - pkg.DefineGoNativeConstValue("BestCompression", gzip.BestCompression) - pkg.DefineGoNativeConstValue("BestSpeed", gzip.BestSpeed) - return pkg, pkg.NewPackage() - case "context": - pkg := gno.NewPackageNode("context", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf((*context.Context)(nil)).Elem()) - pkg.DefineGoNativeValue("WithValue", context.WithValue) - pkg.DefineGoNativeValue("Background", context.Background) - return pkg, pkg.NewPackage() - case "sync": - pkg := gno.NewPackageNode("sync", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(sync.Mutex{})) - pkg.DefineGoNativeType(reflect.TypeOf(sync.RWMutex{})) - pkg.DefineGoNativeType(reflect.TypeOf(sync.Pool{})) - return pkg, pkg.NewPackage() - case "sync/atomic": - pkg := gno.NewPackageNode("atomic", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(atomic.Value{})) - return pkg, pkg.NewPackage() - case "math/big": - pkg := gno.NewPackageNode("big", pkgPath, nil) - pkg.DefineGoNativeValue("NewInt", big.NewInt) - return pkg, pkg.NewPackage() - case "flag": - pkg := gno.NewPackageNode("flag", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(flag.Flag{})) - return pkg, pkg.NewPackage() - case "io": - pkg := gno.NewPackageNode("io", pkgPath, nil) - pkg.DefineGoNativeValue("EOF", io.EOF) - pkg.DefineGoNativeValue("NopCloser", io.NopCloser) - pkg.DefineGoNativeValue("ReadFull", io.ReadFull) - pkg.DefineGoNativeValue("ReadAll", io.ReadAll) - pkg.DefineGoNativeType(reflect.TypeOf((*io.ReadCloser)(nil)).Elem()) - pkg.DefineGoNativeType(reflect.TypeOf((*io.Closer)(nil)).Elem()) - pkg.DefineGoNativeType(reflect.TypeOf((*io.Reader)(nil)).Elem()) - return pkg, pkg.NewPackage() - case "log": - pkg := gno.NewPackageNode("log", pkgPath, nil) - pkg.DefineGoNativeValue("Fatal", log.Fatal) - return pkg, pkg.NewPackage() - case "text/template": - pkg := gno.NewPackageNode("template", pkgPath, nil) - pkg.DefineGoNativeType(reflect.TypeOf(template.FuncMap{})) - return pkg, pkg.NewPackage() - case "unicode/utf8": - pkg := gno.NewPackageNode("utf8", pkgPath, nil) - pkg.DefineGoNativeValue("DecodeRuneInString", utf8.DecodeRuneInString) - tv := gno.TypedValue{T: gno.UntypedRuneType} // TODO dry - tv.SetInt32(utf8.RuneSelf) // .. - pkg.Define("RuneSelf", tv) // .. - return pkg, pkg.NewPackage() - case "errors": - pkg := gno.NewPackageNode("errors", pkgPath, nil) - pkg.DefineGoNativeValue("New", errors.New) - return pkg, pkg.NewPackage() - case "hash/fnv": - pkg := gno.NewPackageNode("fnv", pkgPath, nil) - pkg.DefineGoNativeValue("New32a", fnv.New32a) - return pkg, pkg.NewPackage() - default: - // continue on... - } - } - - // if native package is preferred, try to load stdlibs/* as backup. - if mode == ImportModeNativePreferred { - pn, pv = loadStdlib(rootDir, pkgPath, store, stdout) - if pn != nil { - return - } - } - - // if examples package... - examplePath := filepath.Join(rootDir, "examples", pkgPath) - if osm.DirExists(examplePath) { - memPkg := gno.ReadMemPackage(examplePath, pkgPath) - if memPkg.IsEmpty() { - panic(fmt.Sprintf("found an empty package %q", pkgPath)) - } - - send := std.Coins{} - ctx := TestContext(pkgPath, send) - m2 := gno.NewMachineWithOptions(gno.MachineOptions{ - PkgPath: "test", - Output: stdout, - Store: store, - Context: ctx, - }) - pn, pv = m2.RunMemPackage(memPkg, true) - return - } - return nil, nil - } - db := memdb.NewMemDB() - baseStore := dbadapter.StoreConstructor(db, stypes.StoreOptions{}) - iavlStore := iavl.StoreConstructor(db, stypes.StoreOptions{}) - // make a new store - resStore = gno.NewStore(nil, baseStore, iavlStore) - resStore.SetPackageGetter(getPackage) - resStore.SetNativeStore(teststdlibs.NativeStore) - resStore.SetStrictGo2GnoMapping(false) - return -} - -func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer) (*gno.PackageNode, *gno.PackageValue) { - dirs := [...]string{ - // normal stdlib path. - filepath.Join(rootDir, "gnovm", "stdlibs", pkgPath), - // override path. definitions here override the previous if duplicate. - filepath.Join(rootDir, "gnovm", "tests", "stdlibs", pkgPath), - } - files := make([]string, 0, 32) // pre-alloc 32 as a likely high number of files - for _, path := range dirs { - dl, err := os.ReadDir(path) - if err != nil { - if os.IsNotExist(err) { - continue - } - panic(fmt.Errorf("could not access dir %q: %w", path, err)) - } - - for _, f := range dl { - // NOTE: RunMemPackage has other rules; those should be mostly useful - // for on-chain packages (ie. include README and gno.mod). - if !f.IsDir() && strings.HasSuffix(f.Name(), ".gno") { - files = append(files, filepath.Join(path, f.Name())) - } - } - } - if len(files) == 0 { - return nil, nil - } - - memPkg := gno.ReadMemPackageFromList(files, pkgPath) - m2 := gno.NewMachineWithOptions(gno.MachineOptions{ - // NOTE: see also pkgs/sdk/vm/builtins.go - // Needs PkgPath != its name because TestStore.getPackage is the package - // getter for the store, which calls loadStdlib, so it would be recursively called. - PkgPath: "stdlibload", - Output: stdout, - Store: store, - }) - save := pkgPath != "testing" // never save the "testing" package - return m2.RunMemPackageWithOverrides(memPkg, save) -} - -type dummyReader struct{} - -func (*dummyReader) Read(b []byte) (n int, err error) { - for i := 0; i < len(b); i++ { - b[i] = byte((100 + i) % 256) - } - return len(b), nil -} - -// ---------------------------------------- - -type TestReport struct { - Name string - Verbose bool - Failed bool - Skipped bool - Output string -} diff --git a/gnovm/tests/machine_test.go b/gnovm/tests/machine_test.go deleted file mode 100644 index a67d67f1ff2..00000000000 --- a/gnovm/tests/machine_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package tests - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" -) - -func TestMachineTestMemPackage(t *testing.T) { - matchFunc := func(pat, str string) (bool, error) { return true, nil } - - tests := []struct { - name string - path string - shouldSucceed bool - }{ - { - name: "TestSuccess", - path: "testdata/TestMemPackage/success", - shouldSucceed: true, - }, - { - name: "TestFail", - path: "testdata/TestMemPackage/fail", - shouldSucceed: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // NOTE: Because the purpose of this test is to ensure testing.T.Failed() - // returns true if a gno test is failing, and because we don't want this - // to affect the current testing.T, we are creating an other one thanks - // to testing.RunTests() function. - testing.RunTests(matchFunc, []testing.InternalTest{ - { - Name: tt.name, - F: func(t2 *testing.T) { //nolint:thelper - rootDir := filepath.Join("..", "..") - store := TestStore(rootDir, "test", os.Stdin, os.Stdout, os.Stderr, ImportModeStdlibsOnly) - store.SetLogStoreOps(true) - m := gno.NewMachineWithOptions(gno.MachineOptions{ - PkgPath: "test", - Output: os.Stdout, - Store: store, - Context: nil, - }) - memPkg := gno.ReadMemPackage(tt.path, "test") - - m.TestMemPackage(t2, memPkg) - - if tt.shouldSucceed { - assert.False(t, t2.Failed(), "test %q should have succeed", tt.name) - } else { - assert.True(t, t2.Failed(), "test %q should have failed", tt.name) - } - }, - }, - }) - }) - } -} diff --git a/gnovm/tests/package_test.go b/gnovm/tests/package_test.go deleted file mode 100644 index d4ddfc9a4f0..00000000000 --- a/gnovm/tests/package_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package tests - -import ( - "bytes" - "fmt" - "io/fs" - "log" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/require" - - gno "github.com/gnolang/gno/gnovm/pkg/gnolang" -) - -func TestStdlibs(t *testing.T) { - t.Parallel() - - // NOTE: this test only works using _test.gno files; - // filetests are not meant to be used for testing standard libraries. - // The examples directory is tested directly using `gno test`u - - // find all packages with *_test.gno files. - rootDirs := []string{ - filepath.Join("..", "stdlibs"), - } - testDirs := map[string]string{} // aggregate here, pkgPath -> dir - pkgPaths := []string{} - for _, rootDir := range rootDirs { - fileSystem := os.DirFS(rootDir) - fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - log.Fatal(err) - } - if d.IsDir() { - return nil - } - if strings.HasSuffix(path, "_test.gno") { - dirPath := filepath.Dir(path) - if _, exists := testDirs[dirPath]; exists { - // already exists. - } else { - testDirs[dirPath] = filepath.Join(rootDir, dirPath) - pkgPaths = append(pkgPaths, dirPath) - } - } - return nil - }) - } - // For each package with testfiles (in testDirs), call Machine.TestMemPackage. - for _, pkgPath := range pkgPaths { - testDir := testDirs[pkgPath] - t.Run(pkgPath, func(t *testing.T) { - pkgPath := pkgPath - t.Parallel() - runPackageTest(t, testDir, pkgPath) - }) - } -} - -func runPackageTest(t *testing.T, dir string, path string) { - t.Helper() - - memPkg := gno.ReadMemPackage(dir, path) - require.False(t, memPkg.IsEmpty()) - - stdin := new(bytes.Buffer) - // stdout := new(bytes.Buffer) - stdout := os.Stdout - stderr := new(bytes.Buffer) - rootDir := filepath.Join("..", "..") - store := TestStore(rootDir, path, stdin, stdout, stderr, ImportModeStdlibsOnly) - store.SetLogStoreOps(true) - m := gno.NewMachineWithOptions(gno.MachineOptions{ - PkgPath: "test", - Output: stdout, - Store: store, - Context: nil, - }) - m.TestMemPackage(t, memPkg) - - // Check that machine is empty. - err := m.CheckEmpty() - if err != nil { - t.Log("last state: \n", m.String()) - panic(fmt.Sprintf("machine not empty after main: %v", err)) - } -} diff --git a/gnovm/tests/selector_test.go b/gnovm/tests/selector_test.go deleted file mode 100644 index 1f0b400555b..00000000000 --- a/gnovm/tests/selector_test.go +++ /dev/null @@ -1,174 +0,0 @@ -package tests - -import ( - "fmt" - "reflect" - "testing" -) - -/* -This attempts to show a sufficiently exhaustive list of ValuePaths for -different types of selectors. As can be seen, even a simple selector -expression can represent a number of different types of selectors. -*/ - -// S1 struct -type S1 struct { - F0 int -} - -func (S1) Hello() { -} - -func (*S1) Bye() { -} - -// Pointer to S1 -type S1P *S1 - -// Like S1 but pointer struct -type PS1 *struct { - F0 int -} - -type S7 struct { - S1 -} - -type S9 struct { - *S1 -} - -type S10PD *struct { - S1 -} - -func _printValue(x interface{}) { - if reflect.TypeOf(x).Kind() == reflect.Func { - fmt.Println("function") - } else { - fmt.Println(x) - } -} - -func TestSelectors(t *testing.T) { - t.Parallel() - - x0 := struct{ F0 int }{1} - _printValue(x0.F0) // *ST.F0 - // F:0 - // VPField{depth:0,index:0} - x1 := S1{1} - _printValue(x1.F0) // *DT(S1)>*ST.F0 - // +1 F:0 - // VPField{depth:1,index:0} - _printValue(x1.Hello) // *DT(S1).Hello - // +1 M:0 - // VPValMethod{index:0} - _printValue(x1.Bye) // *PT(implied)>*DT(S1).Bye - // +D +1 *M:1 - // VPDerefPtrMethod{index:1} - x2 := &x0 - _printValue(x2.F0) // *PT>*ST.F0 - // +D F:0 - // VPDerefField{depth:0,index:0} - var x3 PS1 = &struct{ F0 int }{1} - _printValue(x3.F0) // *DT(S1P)>*PT>*ST.F0 - // +1 +D F:0 - // VPDerefField{depth:1,index:0} - x4 := &S1{1} - _printValue(x4.F0) // *PT>*DT(S1P)>*ST.F0 - // +D +1 F:0 - // VPDerefField{depth:2,index:0} - var x5 S1P = &S1{1} - _printValue(x5.F0) // *DT(S1P)>*PT>*DT(S1)>*ST.F0 - // +1 +D +1 F:0 - // VPDerefField{depth:3,index:0} - x6 := &x5 - _printValue(x6) - // _printValue(x6.F0) *PT>*DT(S1P)??? > *PT>*DT(S1)>*ST.F0 - // +D +1 +D +1 F:0 - // VPDerefField{depth:1,index:0}(WRONG!!!) > VPDerefField{depth:1,index:0} XXX ERROR - x7 := S7{S1{1}} - _printValue(x7.F0) // *DT(S7)>*ST.S1 > *DT(S1)>*ST.F0 - // +1 F:0 +1 F:0 - // VPField{depth:1,index:0} > VPField{depth:1,index:0} - x8 := &x7 - _printValue(x8.F0) // *PT>*DT(S7)>*ST.S1 > *DT(S1)>*ST.F0 - // +D +1 F:0 +1 F:0 - // VPDerefField{depth:1,index:0} > VPField{depth:1,index:0} - x9 := S9{x5} - _printValue(x9.F0) // *DT(S9)>*ST.S1 > *PT>*DT(S1)>*ST.F0 - // +1 F:0 +D +1 F:0 - // VPField{depth:1,index:0} > VPDerefField{depth:1,index:0} - x10 := struct{ S1 }{S1{1}} - _printValue(x10.F0) // *ST.S1 > *DT(S1)>*ST.F0 - // F:0 +1 F:0 - // VPField{depth:0,index:0} > VPField{depth:1,index:0} - _printValue(x10.Hello) // *ST.S1 > *DT(S1).Hello - // F:0 +1 M:0 - // VPField{depth:0,index:0} > VPValMethod{index:0} - _printValue(x10.Bye) // (*PT>)*ST.S1 > *DT(S1).Bye - // +S F:0 +1 *M:1 - // VPSubrefField{depth:0,index:0} > VPDerefPtrMethod{index:1} - x10p := &x10 - _printValue(x10p.F0) // *PT>*ST.S1 > *DT(S1)>*ST.F0 - // +D F:0 +1 F:0 - // VPDerefField{depth:0,index:0} > VPField{depth:1,index:0} - _printValue(x10p.Hello) // *PT>*ST.S1 > *DT(S1).Hello - // +D F:0 +1 M:0 - // VPDerefField{depth:0,index:0} > VPValMethod{index:0} - _printValue(x10p.Bye) // *PT>*ST.S1 > *DT(S1).Bye - // +D F:0 +1 *M:1 - // VPSubrefField{depth:0,index:0} > VPDerefPtrMethod{index:1} - var x10pd S10PD = &struct{ S1 }{S1{1}} - _printValue(x10pd.F0) // *DT(S10PD)>*PT>*ST.S1 > *DT(S1)>*ST.F0 - // +1 +D F:0 +1 F:0 - // VPDerefField{depth:1,index:0} > VPField{depth:1,index:0} - // _printValue(x10pd.Hello) *DT(S10PD)>*PT>*ST.S1 > *DT(S1).Hello XXX weird, doesn't work. - // +1 +D F:0 +1 M:0 - // VPDerefField{depth:1,index:0} > VPValMethod{index:0} - _printValue(x10p.Bye) // *DT(S10PD)>*PT>*ST.S1 > *DT(S1).Bye - // +1 +D F:0 +1 *M:1 - // VPSubrefField{depth:1,index:0} > VPDerefPtrMethod{index:1} - x11 := S7{S1{1}} - _printValue(x11.F0) // *DT(S7)>*ST.S1 > *DT(S1)>*ST.F0 NOTE same as x7. - // +1 F:0 +1 F:0 - // VPField{depth:1,index:0} > VPField{depth:1,index:0} - _printValue(x11.Hello) // *DT(S7)>*ST.S1 > *DT(S1)>*ST.Hello - // +1 F:0 +1 M:0 - // VPField{depth:1,index:0} > VPValMethod{index:0} - _printValue(x11.Bye) // (*PT>)*DT(S7)>*ST.S1 > *DT(S1).Bye - // +S +1 F:0 +1 *M:1 - // VPSubrefField{depth:2,index:0} > VPDerefPtrMethod{index:1} - x11p := &S7{S1{1}} - _printValue(x11p.F0) // *PT>*DT(S7)>*ST.S1 > *DT(S1)>*ST.F0 - // +1 F:0 +1 F:0 - // VPDerefField{depth:2,index:0} > VPField{depth:1,index:0} - _printValue(x11p.Hello) // *PT>*DT(S7)>*ST.S1 > *DT(S1).Hello - // +1 F:0 +1 M:0 - // VPDerefField{depth:2,index:0} > VPValMethod{index:0} - _printValue(x11p.Bye) // *PT>*DT(S7)>*ST.S1 > *DT(S1).Bye - // +1 F:0 +1 *M:1 - // VPSubrefField{depth:2,index:0} > VPDerefPtrMethod{index:1} - x12 := struct{ *S1 }{&S1{1}} - _printValue(x12.F0) // *ST.S1 > *PT>*DT(S1)>*ST.F0 - // F:0 +D +1 F:0 - // VPField{depth:0,index:0} > VPDerefField{depth:1,index:0} - _printValue(x12.Hello) // *ST.S1 > *PT>*DT(S1).Hello - // F:0 +D +1 M:0 - // VPField{depth:0,index:0} > VPDerefValMethod{index:0} - _printValue(x12.Bye) // *ST.S1 > *PT>*DT(S1).Bye - // F:0 +D +1 *M:1 - // VPField{depth:0,index:0} > VPDerefPtrMethod{index:1} - x13 := &x12 - _printValue(x13.F0) // *PT>*ST.S1 > *PT>*DT(S1)>*ST.F0 - // +D F:0 +D +1 F:0 - // VPDerefField{depth:0,index:0} > VPDerefField{depth:1,index:0} - _printValue(x13.Hello) // *PT>*ST.S1 > *PT>*DT(S1).Hello - // +D F:0 +D +1 M:0 - // VPDerefField{depth:0,index:0} > VPDerefValMethod{index:0} - _printValue(x13.Bye) // *PT>*ST.S1 > *PT>*DT(S1).Bye - // +D F:0 +D +1 *M:1 - // VPDerefField{depth:0,index:0} > VPDerefPtrMethod{index:1} -} diff --git a/gnovm/tests/stdlibs/generated.go b/gnovm/tests/stdlibs/generated.go index f3d74e214eb..2cc904a9170 100644 --- a/gnovm/tests/stdlibs/generated.go +++ b/gnovm/tests/stdlibs/generated.go @@ -84,18 +84,6 @@ var nativeFuncs = [...]NativeFunc{ p0) }, }, - { - "std", - "ClearStoreCache", - []gno.FieldTypeExpr{}, - []gno.FieldTypeExpr{}, - true, - func(m *gno.Machine) { - testlibs_std.ClearStoreCache( - m, - ) - }, - }, { "std", "callerAt", diff --git a/gnovm/tests/stdlibs/std/std.gno b/gnovm/tests/stdlibs/std/std.gno index 3a56ecc1c47..dcb5a64dbb3 100644 --- a/gnovm/tests/stdlibs/std/std.gno +++ b/gnovm/tests/stdlibs/std/std.gno @@ -3,7 +3,6 @@ package std func AssertOriginCall() // injected func IsOriginCall() bool // injected func TestSkipHeights(count int64) // injected -func ClearStoreCache() // injected func TestSetOrigCaller(addr Address) { testSetOrigCaller(string(addr)) } func TestSetOrigPkgAddr(addr Address) { testSetOrigPkgAddr(string(addr)) } diff --git a/gnovm/tests/stdlibs/std/std.go b/gnovm/tests/stdlibs/std/std.go index d580572e9c5..675194b252f 100644 --- a/gnovm/tests/stdlibs/std/std.go +++ b/gnovm/tests/stdlibs/std/std.go @@ -3,11 +3,11 @@ package std import ( "fmt" "strings" - "testing" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/stdlibs/std" "github.com/gnolang/gno/tm2/pkg/crypto" + tm2std "github.com/gnolang/gno/tm2/pkg/std" ) // TestExecContext is the testing extension of the exec context. @@ -41,9 +41,17 @@ func IsOriginCall(m *gno.Machine) bool { tname := m.Frames[0].Func.Name switch tname { case "main": // test is a _filetest + // 0. main + // 1. $RealmFuncName + // 2. std.IsOriginCall return len(m.Frames) == 3 - case "runtest": // test is a _test - return len(m.Frames) == 7 + case "RunTest": // test is a _test + // 0. testing.RunTest + // 1. tRunner + // 2. $TestFuncName + // 3. $RealmFuncName + // 4. std.IsOriginCall + return len(m.Frames) == 5 } // support init() in _filetest // XXX do we need to distinguish from 'runtest'/_test? @@ -61,23 +69,6 @@ func TestSkipHeights(m *gno.Machine, count int64) { m.Context = ctx } -func ClearStoreCache(m *gno.Machine) { - if gno.IsDebug() && testing.Verbose() { - m.Store.Print() - fmt.Println("========================================") - fmt.Println("CLEAR CACHE (RUNTIME)") - fmt.Println("========================================") - } - m.Store.ClearCache() - m.PreprocessAllFilesAndSaveBlockNodes() - if gno.IsDebug() && testing.Verbose() { - m.Store.Print() - fmt.Println("========================================") - fmt.Println("CLEAR CACHE DONE") - fmt.Println("========================================") - } -} - func X_callerAt(m *gno.Machine, n int) string { if n <= 0 { m.Panic(typedString("GetCallerAt requires positive arg")) @@ -188,6 +179,60 @@ func X_testSetOrigSend(m *gno.Machine, m.Context = ctx } +// TestBanker is a banker that can be used as a mock banker in test contexts. +type TestBanker struct { + CoinTable map[crypto.Bech32Address]tm2std.Coins +} + +var _ std.BankerInterface = &TestBanker{} + +// GetCoins implements the Banker interface. +func (tb *TestBanker) GetCoins(addr crypto.Bech32Address) (dst tm2std.Coins) { + return tb.CoinTable[addr] +} + +// SendCoins implements the Banker interface. +func (tb *TestBanker) SendCoins(from, to crypto.Bech32Address, amt tm2std.Coins) { + fcoins, fexists := tb.CoinTable[from] + if !fexists { + panic(fmt.Sprintf( + "source address %s does not exist", + from.String())) + } + if !fcoins.IsAllGTE(amt) { + panic(fmt.Sprintf( + "source address %s has %s; cannot send %s", + from.String(), fcoins, amt)) + } + // First, subtract from 'from'. + frest := fcoins.Sub(amt) + tb.CoinTable[from] = frest + // Second, add to 'to'. + // NOTE: even works when from==to, due to 2-step isolation. + tcoins, _ := tb.CoinTable[to] + tsum := tcoins.Add(amt) + tb.CoinTable[to] = tsum +} + +// TotalCoin implements the Banker interface. +func (tb *TestBanker) TotalCoin(denom string) int64 { + panic("not yet implemented") +} + +// IssueCoin implements the Banker interface. +func (tb *TestBanker) IssueCoin(addr crypto.Bech32Address, denom string, amt int64) { + coins, _ := tb.CoinTable[addr] + sum := coins.Add(tm2std.Coins{{Denom: denom, Amount: amt}}) + tb.CoinTable[addr] = sum +} + +// RemoveCoin implements the Banker interface. +func (tb *TestBanker) RemoveCoin(addr crypto.Bech32Address, denom string, amt int64) { + coins, _ := tb.CoinTable[addr] + rest := coins.Sub(tm2std.Coins{{Denom: denom, Amount: amt}}) + tb.CoinTable[addr] = rest +} + func X_testIssueCoins(m *gno.Machine, addr string, denom []string, amt []int64) { ctx := m.Context.(*TestExecContext) banker := ctx.Banker diff --git a/gnovm/tests/testdata/TestMemPackage/fail/file_test.gno b/gnovm/tests/testdata/TestMemPackage/fail/file_test.gno deleted file mode 100644 index b202c40bc46..00000000000 --- a/gnovm/tests/testdata/TestMemPackage/fail/file_test.gno +++ /dev/null @@ -1,7 +0,0 @@ -package test - -import "testing" - -func TestFail(t *testing.T) { - t.Errorf("OUPS") -} diff --git a/gnovm/tests/testdata/TestMemPackage/success/file_test.gno b/gnovm/tests/testdata/TestMemPackage/success/file_test.gno deleted file mode 100644 index 0fc1d898199..00000000000 --- a/gnovm/tests/testdata/TestMemPackage/success/file_test.gno +++ /dev/null @@ -1,5 +0,0 @@ -package test - -import "testing" - -func TestSucess(t *testing.T) {}