Yes this is correct, here's my test code:
import "dapple/test.sol";
contract MappingArrayOfStructs is Test {
struct Review {
uint rating;
address reviewer;
string description;
uint dateAdded;
}
mapping (uint => Review[]) ratings;
function testMappingArrayOfStructs() {
//@log push to ratings array
ratings[0].push(Review({
rating: 0,
reviewer: msg.sender,
description: "",
dateAdded: now
}));
//@log `uint ratings[0][0].dateAdded`
}
}
This can be run with dapple test --report
and produces the following report:
MappingArrayOfStructs
test mapping array of structs
LOG: push to ratings array
LOG: 1493284381
Passed!
When you make a state variable public, the compiler automatically generates a getter function as described in the documentation https://solidity.readthedocs.io/en/latest/contracts.html#getter-functions:
function ratings(uint arg1, uint arg2) returns (uint rating, address reviewer, string description, uint dateAdded) {
rating = ratings[arg1][arg2].rating;
reviewer = ratings[arg1][arg2].reviewer;
description = ratings[arg1][arg2].description;
dateAdded = ratings[arg1][arg2].dateAdded;
}
You can access the member data in Solidity like this: var (rating, reviewer, description, dateAdded) = reviews.ratings(0, 0);
If you are using Truffle then the generated bindings treat tuples as arrays, so you can access the member data in JS like this:
var Reviews = artifacts.require("./Reviews.sol");
contract('Reviews', function(accounts) {
it("should return the correct book rating", function() {
var reviews;
return Reviews.deployed().then(function(instance) {
reviews = instance;
return reviews.rateBook(0, 5, "This book changed my life");
}).then(function() {
return reviews.ratings.call(0, 0);
}).then(function(review) {
assert.equal(review[0], 5, "5 wasn't the rating for the book with id 0");
});
});
});
Likewise, a Truffle themed test would work like this:
pragma solidity ^0.4.2;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Reviews.sol";
contract TestReviews {
function testRateBookUsingDeployedContract() {
Reviews reviews = Reviews(DeployedAddresses.Reviews());
reviews.rateBook(0, 5, "Test comment");
var (rating, reviewer, description, dateAdded) = reviews.ratings(0, 0);
Assert.equal(rating, 5, "Book should have a rating of 5");
}
}
On the command line you can simply run these tests using truffle test
and you will get the following output:
Compiling ./contracts/Migrations.sol...
Compiling ./contracts/Reviews.sol...
Compiling ./test/TestReviews.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...
TestReviews
✓ testRateBookUsingDeployedContract (38ms)
Contract: Reviews
✓ should return the correct book rating (65ms)
2 passing (198ms)