Prechádzať zdrojové kódy

Add some struct integration tests for solana

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 4 rokov pred
rodič
commit
90b46a41dd

+ 2 - 2
integration/solana/index.ts

@@ -114,7 +114,7 @@ class TestConnection {
 
         console.log('Program loaded to account', programId.toBase58());
 
-        const returnDataAccount = await this.createStorageAccount(programId, 1024);
+        const returnDataAccount = await this.createStorageAccount(programId, 2048);
         const contractStorageAccount = await this.createStorageAccount(programId, 512);
 
         return new Program(programId, returnDataAccount, contractStorageAccount, abi);
@@ -153,7 +153,7 @@ class Program {
         );
     }
 
-    async call_function(test: TestConnection, name: string, params: string[]): Promise<{ [key: string]: any }> {
+    async call_function(test: TestConnection, name: string, params: any[]): Promise<{ [key: string]: any }> {
         let abi: AbiItem = JSON.parse(this.abi).find((e: AbiItem) => e.name == name);
 
         const input: string = Web3EthAbi.encodeFunctionCall(abi, params);

+ 147 - 0
integration/solana/simple.spec.ts

@@ -244,4 +244,151 @@ describe('Deploy solang contract and test', () => {
 
         }
     });
+
+    it('structs', async function () {
+        this.timeout(50000);
+
+        let conn = await establishConnection();
+
+        let prog = await conn.loadProgram("store.so", "store.abi");
+
+        // call the constructor
+        await prog.call_constructor(conn, []);
+
+        function returns(res: Object) {
+            let arr = Object.values(res);
+            let length = arr.pop()
+            expect(arr.length).toEqual(length);
+            return JSON.stringify(arr);
+        }
+
+        await prog.call_function(conn, "set_foo1", []);
+
+        // get foo1
+        let res = returns(await prog.call_function(conn, "get_both_foos", []));
+
+        // compare without JSON.stringify() results in "Received: serializes to the same string" error.
+        // I have no idea why
+        expect(res).toStrictEqual(JSON.stringify([
+            [
+                "1",
+                "0x446f6e277420636f756e7420796f757220636869636b656e73206265666f72652074686579206861746368",
+                "-102",
+                "0xedaeda",
+                "You can't have your cake and eat it too",
+                [true, "There are other fish in the sea"]
+            ],
+            [
+                "0",
+                "0x",
+                "0",
+                "0x000000",
+                "",
+                [false, ""]
+            ]
+        ]));
+
+        await prog.call_function(conn, "set_foo2", [
+            [
+                "1",
+                "0xb52b073595ccb35eaebb87178227b779",
+                "-123112321",
+                "0x123456",
+                "Barking up the wrong tree",
+                [true, "Drive someone up the wall"]
+            ],
+            "nah"
+        ]);
+
+        res = returns(await prog.call_function(conn, "get_both_foos", []));
+
+        expect(res).toStrictEqual(JSON.stringify([
+            [
+                "1",
+                "0x446f6e277420636f756e7420796f757220636869636b656e73206265666f72652074686579206861746368",
+                "-102",
+                "0xedaeda",
+                "You can't have your cake and eat it too",
+                [true, "There are other fish in the sea"]
+            ],
+            [
+                "1",
+                "0xb52b073595ccb35eaebb87178227b779",
+                "-123112321",
+                "0x123456",
+                "Barking up the wrong tree",
+                [true, "nah"]
+            ]
+        ]));
+
+        await prog.call_function(conn, "delete_foo", [true]);
+
+        res = returns(await prog.call_function(conn, "get_foo", [false]));
+
+        expect(res).toStrictEqual(JSON.stringify([
+            [
+                "1",
+                "0xb52b073595ccb35eaebb87178227b779",
+                "-123112321",
+                "0x123456",
+                "Barking up the wrong tree",
+                [true, "nah"]
+            ],
+        ]));
+
+        res = returns(await prog.call_function(conn, "get_foo", [true]));
+
+        expect(res).toStrictEqual(JSON.stringify([
+            [
+                "0",
+                "0x",
+                "0",
+                "0x000000",
+                "",
+                [false, ""]
+            ],
+        ]));
+
+        await prog.call_function(conn, "delete_foo", [false]);
+
+        res = returns(await prog.call_function(conn, "get_both_foos", []));
+
+        // compare without JSON.stringify() results in "Received: serializes to the same string" error.
+        // I have no idea why
+        expect(res).toStrictEqual(JSON.stringify([
+            [
+                "0",
+                "0x",
+                "0",
+                "0x000000",
+                "",
+                [false, ""]
+            ],
+            [
+                "0",
+                "0x",
+                "0",
+                "0x000000",
+                "",
+                [false, ""]
+            ]
+        ]));
+
+        await prog.call_function(conn, "struct_literal", []);
+
+        res = returns(await prog.call_function(conn, "get_foo", [true]));
+
+        // compare without JSON.stringify() results in "Received: serializes to the same string" error.
+        // I have no idea why
+        expect(res).toStrictEqual(JSON.stringify([
+            [
+                "3",
+                "0x537570657263616c6966726167696c697374696365787069616c69646f63696f7573",
+                "64927",
+                "0xe282ac",
+                "Antidisestablishmentarianism",
+                [true, "Pseudopseudohypoparathyroidism"],
+            ]
+        ]));
+    });
 });

+ 96 - 4
integration/solana/storage.sol

@@ -1,5 +1,21 @@
+ // ethereum solc wants his pragma
+pragma abicoder v2;
+
 contract store {
     enum enum_bar { bar1, bar2, bar3, bar4 }
+    struct struct_foo {
+        enum_bar f1;
+        bytes f2;
+        int64 f3;
+        bytes3 f4;
+        string f5;
+        inner_foo f6;
+    }
+
+    struct inner_foo {
+        bool in1;
+        string in2;
+    }
 
     uint64 u64;
     uint32 u32;
@@ -10,6 +26,8 @@ contract store {
     bytes bs = hex"b00b1e";
     bytes4 fixedbytes;
     enum_bar bar;
+    struct_foo foo1;
+    struct_foo foo2;
 
     function set_values() public {
         u64 = type(uint64).max;
@@ -26,7 +44,7 @@ contract store {
         return (u64, u32, i16, i256);
     }
 
-    function get_values2() public view returns (uint256, string, bytes, bytes4, enum_bar) {
+    function get_values2() public view returns (uint256, string memory, bytes memory, bytes4, enum_bar) {
         return (u256, str, bs, fixedbytes, bar);
     }
 
@@ -49,15 +67,89 @@ contract store {
         bs.push();
     }
 
-    function push(byte b) public {
+    function push(bytes1 b) public {
         bs.push(b);
     }
 
     function pop() public returns (byte) {
+        // note: ethereum solidity bytes.pop() does not return a value
         return bs.pop();
     }
 
-    function get_bs() public view returns (bytes) {
+    function get_bs() public view returns (bytes memory) {
         return bs;
     }
-}
+
+    // function for setting the in2 field in either contract storage or memory
+    function set_storage_in2(struct_foo storage f, string memory v) internal {
+        f.f6.in2 = v;
+    }
+
+    // A memory struct is passed by memory reference (pointer)
+    function set_in2(struct_foo memory f, string memory v) pure internal {
+        f.f6.in2 = v;
+    }
+
+    function get_both_foos() public view returns (struct_foo memory, struct_foo memory) {
+        return (foo1, foo2);
+    }
+
+    function get_foo(bool first) public view returns (struct_foo memory) {
+        struct_foo storage f;
+
+        if (first) {
+            f = foo1;
+        } else {
+            f = foo2;
+        }
+
+        return f;
+    }
+
+    function set_foo2(struct_foo f, string v) public {
+        set_in2(f, v);
+        foo2 = f;
+    }
+
+    function set_foo1() public {
+        foo1.f1 = enum_bar.bar2;
+        foo1.f2 = "Don't count your chickens before they hatch";
+        foo1.f3 = -102;
+        foo1.f4 = hex"edaeda";
+        foo1.f5 = "You can't have your cake and eat it too";
+        foo1.f6.in1 = true;
+
+        set_storage_in2(foo1, 'There are other fish in the sea');
+    }
+
+    function delete_foo(bool first) public {
+        struct_foo storage f;
+
+        if (first) {
+            f = foo1;
+        } else {
+            f = foo2;
+        }
+
+        delete f;
+    }
+
+    function struct_literal() public {
+        // declare a struct literal with fields. There is an
+        // inner struct literal which uses positions
+        struct_foo literal = struct_foo({
+            f1: enum_bar.bar4,
+            f2: "Supercalifragilisticexpialidocious",
+            f3: 0xeffedead1234,
+            f4: unicode'€',
+            f5: "Antidisestablishmentarianism",
+            f6: inner_foo(true, "Pseudopseudohypoparathyroidism")
+        });
+
+        // a literal is just a regular memory struct which can be modified
+        literal.f3 = 0xfd9f;
+
+        // now assign it to a storage variable; it will be copied to contract storage
+        foo1 = literal;
+    }
+}