提交 f21c658b 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #536 from EOSIO/string-class

String class
......@@ -58,6 +58,19 @@ extern "C" {
*/
void* memcpy( void* destination, const void* source, uint32_t num );
/**
* Compare block of memory from source to destination.
* @brief Copy a block of memory from source to destination.
* @param ptr1 Pointer to first data to compare
* @param ptr2 Pointer to second data to compare
* @param num Number of bytes to compare.
*
* @return the destination pointer
*
*/
int32_t memcmp( void* ptr1, const void* ptr2, uint32_t num );
/**
* Fill block of memory.
* @brief Fill a block of memory with the provided value.
......
......@@ -31,6 +31,19 @@ extern "C" {
*/
void prints( const char* cstr );
/**
* Prints string up to given length
* @brief Prints string
* @param cstr - pointer to string
* @param len - len of string to be printed
*
* Example:
* @code
* prints_l("Hello World!", 5); // Output: Hello
* @endcode
*/
void prints_l( const char* cstr, uint32_t len);
/**
* Prints value as a 64 bit unsigned integer
* @brief Prints value as a 64 bit unsigned integer
......
#pragma once
#include <eoslib/types.hpp>
#include <eoslib/system.h>
#include <eoslib/memory.hpp>
#include <eoslib/print.hpp>
namespace eos {
class string {
private:
uint32_t size; // size of the string
char* data; // underlying data
bool own_memory; // true if the object is responsible to clean the memory
uint32_t* refcount; // shared reference count to the underlying data
// Release data if no more string reference to it
void release_data_if_needed() {
if (own_memory && refcount != nullptr) {
(*refcount)--;
if (*refcount == 0) {
free(data);
}
}
}
public:
/**
* Default constructor
*/
string() : size(0), data(nullptr), own_memory(false), refcount(nullptr) {
}
/**
* Constructor to create string with reserved space
* @param s size to be reserved (in number o)
*/
string(uint32_t s) : size(s), own_memory(true) {
data = (char *)malloc(s * sizeof(char));
refcount = (uint32_t*)malloc(sizeof(uint32_t));
*refcount = 1;
}
/**
* Constructor to create string with given data and size
* @param d data
* @param s size of the string (in number of bytes)
* @param copy true to have the data copied and owned by the object
*/
string(char* d, uint32_t s, bool copy) {
assign(d, s, copy);
}
// Copy constructor
string(const string& obj) {
if (this != &obj) {
data = obj.data;
size = obj.size;
own_memory = obj.own_memory;
refcount = obj.refcount;
if (refcount != nullptr) (*refcount)++;
}
}
// Destructor
~string() {
release_data_if_needed();
}
// Get size of the string (in number of bytes)
const uint32_t get_size() const {
return size;
}
// Get the underlying data of the string
const char* get_data() const {
return data;
}
// Check if it owns memory
const bool is_own_memory() const {
return own_memory;
}
// Get the ref count
const uint32_t get_refcount() const {
return *refcount;
}
/**
* Assign string with new data and size
* @param d data
* @param s size (in number of bytes)
* @param copy true to have the data copied and owned by the object
* @return the current string
*/
string& assign(char* d, uint32_t s, bool copy) {
release_data_if_needed();
if (copy) {
data = (char *)malloc(s * sizeof(char));
memcpy(data, d, s * sizeof(char));
own_memory = true;
refcount = (uint32_t*)malloc(sizeof(uint32_t));
*refcount = 1;
} else {
data = d;
own_memory = false;
refcount = nullptr;
}
size = s;
return *this;
}
/**
* Create substring from current string
* @param offset offset from the current string's data
* @param substr_size size of the substring
* @param copy true to have the data copied and owned by the object
* @return substring of the current string
*/
string substr(uint32_t offset, uint32_t substr_size, bool copy) {
assert((offset < size) && (offset + substr_size < size), "out of bound");
return string(data + offset, substr_size, copy);
}
char operator [] (const uint32_t index) {
assert(index < size, "index out of bound");
return *(data + index);
}
string& operator = (const string& obj) {
if (this != &obj) {
release_data_if_needed();
data = obj.data;
size = obj.size;
own_memory = obj.own_memory;
refcount = obj.refcount;
if (refcount != nullptr) (*refcount)++;
}
return *this;
}
string& operator += (const string& str){
assert((size + str.size > size) && (size + str.size > str.size), "overflow");
char* new_data;
uint32_t new_size;
if (size > 0 && *(data + size - 1) == '\0') {
// Null terminated string, remove the \0 when concatenates
new_size = size - 1 + str.size;
new_data = (char *)malloc(new_size * sizeof(char));
memcpy(new_data, data, (size - 1) * sizeof(char));
memcpy(new_data + size - 1, str.data, str.size * sizeof(char));
} else {
new_size = size + str.size;
new_data = (char *)malloc(new_size * sizeof(char));
memcpy(new_data, data, size * sizeof(char));
memcpy(new_data + size, str.data, str.size * sizeof(char));
}
// Release old data
release_data_if_needed();
// Assign new data
data = new_data;
size = new_size;
own_memory = true;
refcount = (uint32_t*)malloc(sizeof(uint32_t));
*refcount = 1;
return *this;
}
// Compare two strings
// Return an integral value indicating the relationship between strings
// >0 if the first string is greater than the second string
// 0 if both strings are equal
// <0 if the first string is smaller than the second string
// The return value also represents the difference between the first character that doesn't match of the two strings
int32_t compare(const string& str) const {
int32_t result;
if (size == str.size) {
result = memcmp(data, str.data, size);
} else if (size < str.size) {
result = memcmp(data, str.data, size);
if (result == 0) {
// String is equal up to size of the shorter string, return the difference in byte of the next character
result = 0 - (unsigned char)str.data[size];
}
} else if (size > str.size) {
result = memcmp(data, str.data, str.size);
if (result == 0) {
// String is equal up to size of the shorter string, return the difference in byte of the next character
result = (unsigned char)data[str.size];
}
}
return result;
}
friend bool operator < (const string& lhs, const string& rhs) {
return lhs.compare(rhs) < 0;
}
friend bool operator > (const string& lhs, const string& rhs) {
return lhs.compare(rhs) > 0;
}
friend bool operator == (const string& lhs, const string& rhs) {
return lhs.compare(rhs) == 0;
}
friend bool operator != (const string& lhs, const string& rhs) {
return lhs.compare(rhs) != 0;
}
friend string operator + (string lhs, const string& rhs) {
return lhs += rhs;
}
void print() const {
if (size > 0 && *(data + size - 1) == '\0') {
// Null terminated string
prints(data);
} else {
// Non null terminated string
// We need to specify the size of string so it knows where to stop
prints_l(data, size);
}
}
};
}
......@@ -77,10 +77,29 @@ extern "C" {
WASM_TEST_HANDLER(test_transaction, send_transaction_empty);
WASM_TEST_HANDLER(test_transaction, send_transaction_max);
WASM_TEST_HANDLER(test_transaction, send_transaction_large);
//test chain
WASM_TEST_HANDLER(test_chain, test_activeprods);
// test string
WASM_TEST_HANDLER(test_string, construct_with_size);
WASM_TEST_HANDLER(test_string, construct_with_data);
WASM_TEST_HANDLER(test_string, construct_with_data_copied);
WASM_TEST_HANDLER(test_string, construct_with_data_partially);
WASM_TEST_HANDLER(test_string, copy_constructor);
WASM_TEST_HANDLER(test_string, assignment_operator);
WASM_TEST_HANDLER(test_string, index_operator);
WASM_TEST_HANDLER(test_string, index_out_of_bound);
WASM_TEST_HANDLER(test_string, substring);
WASM_TEST_HANDLER(test_string, substring_out_of_bound);
WASM_TEST_HANDLER(test_string, concatenation_null_terminated);
WASM_TEST_HANDLER(test_string, concatenation_non_null_terminated);
WASM_TEST_HANDLER(test_string, assign);
WASM_TEST_HANDLER(test_string, comparison_operator);
WASM_TEST_HANDLER(test_string, print_null_terminated);
WASM_TEST_HANDLER(test_string, print_non_null_terminated);
WASM_TEST_HANDLER(test_string, print_unicode);
//unhandled test call
WASM_TEST_ERROR_CODE = WASM_TEST_FAIL;
}
......
......@@ -128,3 +128,23 @@ struct test_transaction {
struct test_chain {
static unsigned int test_activeprods();
};
struct test_string {
static unsigned int construct_with_size();
static unsigned int construct_with_data();
static unsigned int construct_with_data_copied();
static unsigned int construct_with_data_partially();
static unsigned int copy_constructor();
static unsigned int assignment_operator();
static unsigned int index_operator();
static unsigned int index_out_of_bound();
static unsigned int substring();
static unsigned int substring_out_of_bound();
static unsigned int concatenation_null_terminated();
static unsigned int concatenation_non_null_terminated();
static unsigned int assign();
static unsigned int comparison_operator();
static unsigned int print_null_terminated();
static unsigned int print_non_null_terminated();
static unsigned int print_unicode();
};
#include <eoslib/string.hpp>
#include <eoslib/eos.hpp>
#include "test_api.hpp"
unsigned int test_string::construct_with_size() {
uint32_t size = 100;
eos::string str(size);
WASM_ASSERT( str.get_size() == size, "str.get_size() == size" );
return WASM_TEST_PASS;
}
unsigned int test_string::construct_with_data() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
WASM_ASSERT( str.get_size() == size, "str.get_size() == size" );
WASM_ASSERT( str.get_data() == data, "str.get_data() == data" );
WASM_ASSERT( str.is_own_memory() == false, "str.is_own_memory() == false" );
return WASM_TEST_PASS;
}
unsigned int test_string::construct_with_data_partially() {
char data[] = "abcdefghij";
uint32_t substr_size = 5;
uint32_t offset = 2;
eos::string str(data + offset, substr_size, false);
WASM_ASSERT( str.get_size() == substr_size, "str.get_size() == substr_size" );
WASM_ASSERT( str.get_data() == data + offset, "str.get_data() == data + offset" );
for (uint8_t i = offset; i < substr_size; i++) {
WASM_ASSERT( str[i] == data[offset + i], "str[i] == data[offset + i]" );
}
WASM_ASSERT( str.is_own_memory() == false, "str.is_own_memory() == false" );
return WASM_TEST_PASS;
}
unsigned int test_string::construct_with_data_copied() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, true);
WASM_ASSERT( str.get_size() == size, "str.get_size() == size" );
WASM_ASSERT( str.get_data() != data, "str.get_data() != data" );
for (uint8_t i = 0; i < size; i++) {
WASM_ASSERT( str[i] == data[i], "str[i] == data[i]" );
}
WASM_ASSERT( str.is_own_memory() == true, "str.is_own_memory() == true" );
return WASM_TEST_PASS;
}
unsigned int test_string::copy_constructor() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str1(data, size, true);
eos::string str2 = str1;
WASM_ASSERT( str1.get_size() == str2.get_size(), "str1.get_size() == str2.get_size()" );
WASM_ASSERT( str1.get_data() == str2.get_data(), "str1.get_data() == str2.getget_data_size()" );
WASM_ASSERT( str1.is_own_memory() == str2.is_own_memory(), "str1.is_own_memory() == str2.is_own_memory()" );
WASM_ASSERT( str1.get_refcount() == str2.get_refcount(), "str1.get_refcount() == str2.get_refcount()" );
WASM_ASSERT( str1.get_refcount() == 2, "str1.refcount() == 2" );
return WASM_TEST_PASS;
}
unsigned int test_string::assignment_operator() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str1(data, size, true);
eos::string str2;
str2 = str1;
WASM_ASSERT( str1.get_size() == str2.get_size(), "str1.get_size() == str2.get_size()" );
WASM_ASSERT( str1.get_data() == str2.get_data(), "str1.get_data() == str2.getget_data_size()" );
WASM_ASSERT( str1.is_own_memory() == str2.is_own_memory(), "str1.is_own_memory() == str2.is_own_memory()" );
WASM_ASSERT( str1.get_refcount() == str2.get_refcount(), "str1.get_refcount() == str2.get_refcount()" );
WASM_ASSERT( str1.get_refcount() == 2, "str1.refcount() == 2" );
return WASM_TEST_PASS;
}
unsigned int test_string::index_operator() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
for (uint8_t i = 0; i < size; i++) {
WASM_ASSERT( str[i] == data[i], "str[i] == data[i]" );
}
return WASM_TEST_PASS;
}
unsigned int test_string::index_out_of_bound() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
char c = str[size];
return WASM_TEST_PASS;
}
unsigned int test_string::substring() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
uint32_t substr_size = 5;
uint32_t offset = 2;
eos::string substr = str.substr(offset, substr_size, false);
WASM_ASSERT( substr.get_size() == substr_size, "str.get_size() == substr_size" );
WASM_ASSERT( substr.get_data() == str.get_data() + offset, "substr.get_data() == str.get_data() + offset" );
for (uint8_t i = offset; i < substr_size; i++) {
WASM_ASSERT( substr[i] == str[offset + i], "substr[i] == str[offset + i]" );
}
WASM_ASSERT( substr.is_own_memory() == false, "substr.is_own_memory() == false" );
return WASM_TEST_PASS;
}
unsigned int test_string::substring_out_of_bound() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
uint32_t substr_size = size;
uint32_t offset = 1;
eos::string substr = str.substr(offset, substr_size, false);
return WASM_TEST_PASS;
}
unsigned int test_string::concatenation_null_terminated() {
char data1[] = "abcdefghij";
uint32_t size1 = sizeof(data1)/sizeof(char);
eos::string str1(data1, size1, false);
char data2[] = "klmnoppqrst";
uint32_t size2 = sizeof(data2)/sizeof(char);
eos::string str2(data2, size2, false);
str1 += str2;
WASM_ASSERT( str1.get_data() != data1, "str1.get_data() != data1" );
WASM_ASSERT( str1.get_size() == size1 + size2 - 1, "str1.get_size == size1 + size2 - 1" );
for (uint8_t i = 0; i < size1 - 1; i++) {
WASM_ASSERT( str1[i] == data1[i], "str1[i] == data1[i]" );
}
for (uint8_t i = 0; i < size2; i++) {
WASM_ASSERT( str1[size1 - 1 + i] == data2[i], "str1[i] == data2[i]" );
}
return WASM_TEST_PASS;
}
unsigned int test_string::concatenation_non_null_terminated() {
char data1[] = {'a','b','c','d','e','f','g','h','i','j'};
uint32_t size1 = sizeof(data1)/sizeof(char);
eos::string str1(data1, size1, false);
char data2[] = {'k','l','m','n','o','p','q','r','s','t'};
uint32_t size2 = sizeof(data2)/sizeof(char);
eos::string str2(data2, size2, false);
str1 += str2;
WASM_ASSERT( str1.get_data() != data1, "str1.get_data() != data1" );
WASM_ASSERT( str1.get_size() == size1 + size2, "str1.get_size == size1 + size2" );
for (uint8_t i = 0; i < size1; i++) {
WASM_ASSERT( str1[i] == data1[i], "str1[i] == data1[i]" );
}
for (uint8_t i = 0; i < size2; i++) {
WASM_ASSERT( str1[size1 + i] == data2[i], "str1[i] == data2[i]" );
}
return WASM_TEST_PASS;
}
unsigned int test_string::assign() {
char data[] = "abcdefghij";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(100);
str.assign(data, size, true);
WASM_ASSERT( str.get_size() == size, "str.get_size() == size" );
WASM_ASSERT( str.get_data() != data, "str.get_data() != data" );
for (uint8_t i = 0; i < size; i++) {
WASM_ASSERT( str[i] == data[i], "str[i] == data[i]" );
}
WASM_ASSERT( str.is_own_memory() == true, "str.is_own_memory() == true" );
return WASM_TEST_PASS;
}
unsigned int test_string::comparison_operator() {
char data1[] = "abcdefghij";
uint32_t size1 = sizeof(data1)/sizeof(char);
eos::string str1(data1, size1, false);
char data2[] = "abcdefghij";
uint32_t size2 = sizeof(data2)/sizeof(char);
eos::string str2(data2, size2, false);
char data3[] = "klmno";
uint32_t size3 = sizeof(data3)/sizeof(char);
eos::string str3(data3, size3, false);
char data4[] = "aaaaaaaaaaaaaaa";
uint32_t size4 = sizeof(data4)/sizeof(char);
eos::string str4(data4, size4, false);
char data5[] = "你好";
uint32_t size5 = sizeof(data5)/sizeof(char);
eos::string str5(data5, size5, false);
char data6[] = "你好嗎?";
uint32_t size6 = sizeof(data6)/sizeof(char);
eos::string str6(data6, size6, false);
char data7[] = {'a', 'b', 'c', 'd', 'e'};
uint32_t size7 = sizeof(data7)/sizeof(char);
eos::string str7(data7, size7, false);
char data8[] = {'a', 'b', 'c'};
uint32_t size8 = sizeof(data8)/sizeof(char);
eos::string str8(data8, size8, false);
WASM_ASSERT( str1 == str2, "str1 == str2" );
WASM_ASSERT( str1 != str3, "str1 != str3" );
WASM_ASSERT( str1 < str3, "str1 < str3" );
WASM_ASSERT( str2 > str4, "str2 > str4" );
WASM_ASSERT( str1.compare(str2) == 0, "str1.compare(str2) == 0" );
WASM_ASSERT( str1.compare(str3) < 0, "str1.compare(str3) < 0" );
WASM_ASSERT( str1.compare(str4) > 0, "str1.compare(str4) > 0" );
WASM_ASSERT( str5.compare(str6) < 0, "st5.compare(str6) < 0" );
WASM_ASSERT( str7.compare(str8) > 0, "str7.compare(str8) > 0" );
return WASM_TEST_PASS;
}
unsigned int test_string::print_null_terminated() {
char data[] = "Hello World!";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
eos::print(str);
return WASM_TEST_PASS;
}
unsigned int test_string::print_non_null_terminated() {
char data[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
eos::print(str);
return WASM_TEST_PASS;
}
unsigned int test_string::print_unicode() {
char data[] = "你好,世界!";
uint32_t size = sizeof(data)/sizeof(char);
eos::string str(data, size, false);
eos::print(str);
return WASM_TEST_PASS;
}
......@@ -338,6 +338,17 @@ DEFINE_INTRINSIC_FUNCTION3(env,memcpy,memcpy,i32,i32,dstp,i32,srcp,i32,len) {
return dstp;
}
DEFINE_INTRINSIC_FUNCTION3(env,memcmp,memcmp,i32,i32,dstp,i32,srcp,i32,len) {
auto& wasm = wasm_interface::get();
auto mem = wasm.current_memory;
char* dst = memoryArrayPtr<char>( mem, dstp, len);
const char* src = memoryArrayPtr<const char>( mem, srcp, len );
FC_ASSERT( len > 0 );
return memcmp( dst, src, uint32_t(len) );
}
DEFINE_INTRINSIC_FUNCTION3(env,memset,memset,i32,i32,rel_ptr,i32,value,i32,len) {
auto& wasm = wasm_interface::get();
auto mem = wasm.current_memory;
......@@ -525,10 +536,19 @@ DEFINE_INTRINSIC_FUNCTION1(env,prints,prints,none,i32,charptr) {
std::cerr << std::string( str, strnlen(str, wasm.current_state->mem_end-charptr) );
}
DEFINE_INTRINSIC_FUNCTION2(env,prints_l,prints_l,none,i32,charptr,i32,len) {
auto& wasm = wasm_interface::get();
auto mem = wasm.current_memory;
const char* str = &memoryRef<const char>( mem, charptr );
std::cerr << std::string( str, len );
}
DEFINE_INTRINSIC_FUNCTION2(env,printhex,printhex,none,i32,data,i32,datalen) {
auto& wasm = wasm_interface::get();
auto mem = wasm.current_memory;
char* buff = memoryArrayPtr<char>(mem, data, datalen);
std::cerr << fc::to_hex(buff, datalen) << std::endl;
}
......
......@@ -430,6 +430,30 @@ BOOST_FIXTURE_TEST_CASE(test_all, testing_fixture)
std::copy(gpo.active_producers.begin(), gpo.active_producers.end(), prods.begin());
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_chain", "test_activeprods"), {}, fc::raw::pack(prods) ) == WASM_TEST_PASS, "test_chain::test_activeprods()" );
// Test string
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_size"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_size()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_data"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_data()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_data_copied"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_data_copied()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "construct_with_data_partially"), {}, {} ) == WASM_TEST_PASS, "test_string::construct_with_data_partially()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "copy_constructor"), {}, {} ) == WASM_TEST_PASS, "test_string::copy_constructor()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "assignment_operator"), {}, {} ) == WASM_TEST_PASS, "test_string::assignment_operator()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "index_operator"), {}, {} ) == WASM_TEST_PASS, "test_string::index_operator()" );
BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "index_out_of_bound"), {}, {} ), fc::assert_exception, is_assert_exception );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "substring"), {}, {} ) == WASM_TEST_PASS, "test_string::substring()" );
BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "substring_out_of_bound"), {}, {} ), fc::assert_exception, is_assert_exception );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "concatenation_null_terminated"), {}, {} ) == WASM_TEST_PASS, "test_string::concatenation_null_terminated()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "concatenation_non_null_terminated"), {}, {} ) == WASM_TEST_PASS, "test_string::concatenation_non_null_terminated()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "assign"), {}, {} ) == WASM_TEST_PASS, "test_string::assign()" );
BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_string", "comparison_operator"), {}, {} ) == WASM_TEST_PASS, "test_string::comparison_operator()" );
CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_string", "print_null_terminated"), {}, {}) );
BOOST_CHECK_EQUAL( capture.size() , 1);
BOOST_CHECK_EQUAL( capture[0], "Hello World!");
CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_string", "print_non_null_terminated"), {}, {}) );
BOOST_CHECK_EQUAL( capture.size() , 1);
BOOST_CHECK_EQUAL( capture[0], "Hello World!");
CAPTURE(cerr, CALL_TEST_FUNCTION( TEST_METHOD("test_string", "print_unicode"), {}, {}) );
BOOST_CHECK_EQUAL( capture.size() , 1);
BOOST_CHECK_EQUAL( capture[0], "你好,世界!");
} FC_LOG_AND_RETHROW() }
......@@ -482,6 +506,9 @@ BOOST_FIXTURE_TEST_CASE(test_case_name, testing_fixture)
//Test wasm memory allocation
MEMORY_TEST_CASE(test_memory, testmemory, memory_test_wast)
//Test memcmp
MEMORY_TEST_CASE(test_memcmp, testmemcmp, memory_test_wast)
//Test wasm memory allocation at boundaries
MEMORY_TEST_CASE(test_memory_bounds, testbounds, memory_test_wast)
......
......@@ -168,6 +168,24 @@ extern "C" {
memcpy(buf3, &buf3[49], 50);
}
void test_memcmp()
{
char buf1[] = "abcde";
char buf2[] = "abcde";
int32_t res1 = memcmp(buf1, buf2, 6);
assert(res1 == 0, "first data should be equal to second data");
char buf3[] = "abcde";
char buf4[] = "fghij";
int32_t res2 = memcmp(buf3, buf4, 6);
assert(res2 < 0, "first data should be smaller than second data");
char buf5[] = "fghij";
char buf6[] = "abcde";
int32_t res3 = memcmp(buf5, buf6, 6);
assert(res3 > 0, "first data should be larger than second data");
}
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t action )
{
......@@ -206,5 +224,12 @@ extern "C" {
test_memcpy_overlap_end();
}
}
else if( code == N(testmemcmp) )
{
if( action == N(transfer) )
{
test_memcmp();
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册