Import Mbed OS hard-float snapshot
This commit is contained in:
1
storage/blockdevice/tests/UNITTESTS/.mbedignore
Normal file
1
storage/blockdevice/tests/UNITTESTS/.mbedignore
Normal file
@@ -0,0 +1 @@
|
||||
*
|
||||
@@ -0,0 +1,318 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/BufferedBlockDevice.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::ReturnArg;
|
||||
using ::testing::SaveArg;
|
||||
using ::testing::SaveArgPointee;
|
||||
using ::testing::SetArrayArgument;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::SetArgReferee;
|
||||
using ::testing::DoAll;
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
|
||||
class BufferedBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
BufferedBlockDevice bd{&bd_mock};
|
||||
uint8_t *magic;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_CALL(bd_mock, get_read_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock, get_program_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock, size()).WillOnce(Return(DEVICE_SIZE));
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[2*BLOCK_SIZE];
|
||||
buf = new uint8_t[2*BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE*2; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
buf[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
EXPECT_CALL(bd_mock, sync()); // Called on deinit
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, init)
|
||||
{
|
||||
BufferedBlockDevice b(&bd_mock);
|
||||
EXPECT_EQ(b.get_erase_size(), 0);
|
||||
EXPECT_EQ(b.get_erase_size(0), 0);
|
||||
EXPECT_EQ(b.get_erase_value(), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.size(), 0);
|
||||
EXPECT_EQ(b.program(magic, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.read(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.trim(0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.deinit(), BD_ERROR_OK);
|
||||
EXPECT_EQ(b.sync(), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.erase(0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_CALL(bd_mock, size()).WillOnce(Return(DEVICE_SIZE));
|
||||
EXPECT_CALL(bd_mock, get_read_size()).WillOnce(Return(DEVICE_SIZE));
|
||||
EXPECT_CALL(bd_mock, get_program_size()).WillOnce(Return(DEVICE_SIZE));
|
||||
|
||||
EXPECT_EQ(b.init(), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, get_erase_size()).WillOnce(Return(17));
|
||||
EXPECT_CALL(bd_mock, get_erase_size(0)).WillOnce(Return(18));
|
||||
EXPECT_CALL(bd_mock, get_erase_value()).WillOnce(Return(19));
|
||||
EXPECT_CALL(bd_mock, get_type()).WillOnce(Return("mytype"));
|
||||
|
||||
EXPECT_EQ(b.get_erase_size(), 17);
|
||||
EXPECT_EQ(b.get_erase_size(0), 18);
|
||||
EXPECT_EQ(b.get_erase_value(), 19);
|
||||
EXPECT_EQ(b.get_program_size(), 1);
|
||||
EXPECT_EQ(b.get_read_size(), 1);
|
||||
EXPECT_EQ(b.size(), DEVICE_SIZE);
|
||||
EXPECT_EQ(b.get_type(), "mytype");
|
||||
|
||||
EXPECT_CALL(bd_mock, deinit()); // Called in b's destructor
|
||||
EXPECT_CALL(bd_mock, sync()); // Called on b's deinit
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, read_full_block)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, is_valid_read(0, BLOCK_SIZE))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(0, bd.read(buf, 0, BLOCK_SIZE));
|
||||
EXPECT_EQ(0, memcmp(magic, buf, BLOCK_SIZE));
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, over_read)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, is_valid_read(DEVICE_SIZE - BLOCK_SIZE, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(bd_mock, read(_, DEVICE_SIZE - BLOCK_SIZE, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(bd.read(buf, DEVICE_SIZE - BLOCK_SIZE, BLOCK_SIZE), 0);
|
||||
|
||||
// This will return before mock's is_valid_read()
|
||||
EXPECT_EQ(bd.read(buf, DEVICE_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, unalign_read)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, is_valid_read(BLOCK_SIZE/2, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, BLOCK_SIZE/2, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE/2), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(bd.read(buf, BLOCK_SIZE/2, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(0, memcmp(buf, magic+(BLOCK_SIZE/2), BLOCK_SIZE/2));
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, unalign_erase)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(bd.program("a", BLOCK_SIZE/2, 1), 0);
|
||||
|
||||
ON_CALL(bd_mock, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
|
||||
// Partial erase is not supported
|
||||
EXPECT_EQ(bd.erase(BLOCK_SIZE/2, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, align_big_read)
|
||||
{
|
||||
uint8_t *buffer = new uint8_t[BLOCK_SIZE*2];
|
||||
|
||||
EXPECT_CALL(bd_mock, is_valid_read(0, (BLOCK_SIZE*2)-1))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE*2-1))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE*2-1), Return(BD_ERROR_OK)));
|
||||
|
||||
// Should cause 1 full block to be read unaligned from the device
|
||||
// second block would require buffering, because it is not a full (-1)
|
||||
EXPECT_EQ(bd.read(buffer, 0, (BLOCK_SIZE*2)-1), 0);
|
||||
EXPECT_EQ(0, memcmp(magic, buffer, BLOCK_SIZE));
|
||||
EXPECT_EQ(0, memcmp(magic+BLOCK_SIZE, buffer+BLOCK_SIZE, BLOCK_SIZE-1));
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, program_small_chunks)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, is_valid_read(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
for (int i=0; i < BLOCK_SIZE - 1; ++i) {
|
||||
EXPECT_EQ(bd.program(magic+i, i, 1), 0);
|
||||
}
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE - 1));
|
||||
|
||||
// write cache will be flushed on deinit.
|
||||
EXPECT_CALL(bd_mock, program(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, program_and_read_from_cache)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, program(_, 0, BLOCK_SIZE))
|
||||
.Times(2) // Once on 1st program and once on deinit
|
||||
.WillRepeatedly(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, is_valid_read(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, sync()); // Triggered from program()
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.program("a", 0, 1), 0);
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ('a', buf[0]);
|
||||
EXPECT_EQ(0, memcmp(buf+1, magic+1, BLOCK_SIZE-1));
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, program_and_read_from_device)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, program(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, program(_, BLOCK_SIZE, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, BLOCK_SIZE, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, is_valid_read(BLOCK_SIZE*3, BLOCK_SIZE-1)).WillOnce(Return(false));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, BLOCK_SIZE*3, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE-1), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, sync()).Times(1); // Triggered from program()s
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.program(magic, BLOCK_SIZE, BLOCK_SIZE-1), 0);
|
||||
EXPECT_EQ(bd.read(buf, BLOCK_SIZE*3, BLOCK_SIZE-1), 0);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE-1));
|
||||
|
||||
EXPECT_CALL(bd_mock, is_valid_read(BLOCK_SIZE*3, BLOCK_SIZE+1)).WillOnce(Return(false));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, BLOCK_SIZE*3, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)))
|
||||
.RetiresOnSaturation();
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, BLOCK_SIZE*4, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic+BLOCK_SIZE, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(bd.read(buf, BLOCK_SIZE*3, BLOCK_SIZE+1), 0);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE+1));
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, program_and_verify_from_storage)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, program(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, is_valid_read(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(2)
|
||||
.WillRepeatedly(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, sync()); // Triggered from program()
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE/2), 0);
|
||||
EXPECT_EQ(bd.program(magic+BLOCK_SIZE/2, BLOCK_SIZE/2, BLOCK_SIZE/2), 0); // This should actually write to device
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
|
||||
}
|
||||
|
||||
TEST_F(BufferedBlockModuleTest, flush_automatically)
|
||||
{
|
||||
// Validate cache
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillRepeatedly(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE/2), 0); // Don't write full block
|
||||
|
||||
// Validate cache for the second program
|
||||
EXPECT_CALL(bd_mock, read(_, BLOCK_SIZE, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillRepeatedly(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, program(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, BLOCK_SIZE, BLOCK_SIZE/2), 0); // This should cause flush() for previous data in cache
|
||||
|
||||
EXPECT_CALL(bd_mock, program(_, BLOCK_SIZE, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/BufferedBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_BufferedBlockDevice.cpp
|
||||
stubs/BlockDevice_mock.h
|
||||
)
|
||||
@@ -0,0 +1,162 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ChainingBlockDevice.cpp"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::ReturnArg;
|
||||
using ::testing::SaveArg;
|
||||
using ::testing::SaveArgPointee;
|
||||
using ::testing::SetArrayArgument;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::SetArgReferee;
|
||||
using ::testing::DoAll;
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define SECTORS_NUM (8)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE * SECTORS_NUM)
|
||||
|
||||
class ChainingBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock1;
|
||||
BlockDeviceMock bd_mock2;
|
||||
|
||||
BlockDevice *bds[2] = {&bd_mock1, &bd_mock2};
|
||||
ChainingBlockDevice bd{bds, 2};
|
||||
uint8_t *magic;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
ON_CALL(bd_mock1, size()).WillByDefault(Return((SECTORS_NUM / 2)*BLOCK_SIZE));
|
||||
ON_CALL(bd_mock2, size()).WillByDefault(Return((SECTORS_NUM )*BLOCK_SIZE));
|
||||
|
||||
ON_CALL(bd_mock1, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock2, get_erase_size(_)).WillByDefault(Return(2*BLOCK_SIZE));
|
||||
|
||||
ON_CALL(bd_mock1, get_erase_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock2, get_erase_size()).WillByDefault(Return(2*BLOCK_SIZE));
|
||||
|
||||
EXPECT_CALL(bd_mock1, init());
|
||||
EXPECT_CALL(bd_mock2, init());
|
||||
// Init performs checks on the parameters of underlying BDs
|
||||
// the BDs used for this test have different parameters:
|
||||
// bd_mock1 has erase/program/read size of BLOCK_SIZE and total (SECTORS_NUM / 2)*BLOCK_SIZE size
|
||||
// bd_mock1 has erase/program/read size of 2*BLOCK_SIZE and total (SECTORS_NUM )*BLOCK_SIZE size
|
||||
EXPECT_CALL(bd_mock1, get_erase_value()).WillOnce(Return(0));
|
||||
EXPECT_CALL(bd_mock1, get_read_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock1, get_program_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
|
||||
EXPECT_CALL(bd_mock2, get_erase_value()).WillOnce(Return(0));
|
||||
EXPECT_CALL(bd_mock2, get_read_size()).WillOnce(Return(BLOCK_SIZE * 2));
|
||||
EXPECT_CALL(bd_mock2, get_program_size()).WillOnce(Return(BLOCK_SIZE * 2));
|
||||
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[BLOCK_SIZE * 4];
|
||||
buf = new uint8_t[BLOCK_SIZE * 4];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE * 4; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
EXPECT_CALL(bd_mock1, deinit());
|
||||
EXPECT_CALL(bd_mock2, deinit());
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ChainingBlockModuleTest, init)
|
||||
{
|
||||
ChainingBlockDevice b(this->bds, 2);
|
||||
EXPECT_EQ(b.get_erase_size(), 0);
|
||||
EXPECT_EQ(b.get_erase_size(0), 0);
|
||||
EXPECT_EQ(b.get_erase_value(), -1);
|
||||
EXPECT_EQ(b.size(), 0);
|
||||
EXPECT_EQ(b.program(magic, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.read(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
// EXPECT_EQ(b.deinit(), BD_ERROR_OK);
|
||||
EXPECT_EQ(b.sync(), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.get_type(), "CHAINING");
|
||||
|
||||
EXPECT_CALL(bd_mock1, init());
|
||||
EXPECT_CALL(bd_mock1, size()).WillOnce(Return((SECTORS_NUM / 2)*BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock1, get_erase_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock1, get_read_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock1, get_program_size()).WillOnce(Return(BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock1, get_erase_value()).WillOnce(Return(2));
|
||||
EXPECT_CALL(bd_mock2, init());
|
||||
EXPECT_CALL(bd_mock2, size()).WillOnce(Return((SECTORS_NUM )*BLOCK_SIZE));
|
||||
EXPECT_CALL(bd_mock2, get_erase_size()).WillOnce(Return(BLOCK_SIZE * 2));
|
||||
EXPECT_CALL(bd_mock2, get_read_size()).WillOnce(Return(BLOCK_SIZE * 2));
|
||||
EXPECT_CALL(bd_mock2, get_program_size()).WillOnce(Return(BLOCK_SIZE * 2));
|
||||
EXPECT_CALL(bd_mock2, get_erase_value()).WillOnce(Return(3));
|
||||
|
||||
EXPECT_EQ(b.init(), 0);
|
||||
|
||||
EXPECT_EQ(b.get_program_size(), BLOCK_SIZE * 2);
|
||||
EXPECT_EQ(b.get_read_size(), BLOCK_SIZE * 2);
|
||||
EXPECT_EQ(b.get_erase_size(), BLOCK_SIZE * 2);
|
||||
EXPECT_EQ(b.get_erase_value(), -1);
|
||||
}
|
||||
|
||||
TEST_F(ChainingBlockModuleTest, memory_overlap)
|
||||
{
|
||||
// program
|
||||
// Half of the data should go into bd_mock1
|
||||
EXPECT_CALL(bd_mock1, program(ByteBufferMatcher(magic, BLOCK_SIZE*2), (SECTORS_NUM / 2 - 2) * BLOCK_SIZE, 2 * BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
// Another half should go to bd_mock2
|
||||
EXPECT_CALL(bd_mock2, program(ByteBufferMatcher(magic+BLOCK_SIZE*2, BLOCK_SIZE*2), 0, 2 * BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, (SECTORS_NUM / 2 - 2) * BLOCK_SIZE, 4 * BLOCK_SIZE), BD_ERROR_OK);
|
||||
|
||||
|
||||
// read
|
||||
// On read half of the data will be read out from bd_mock1
|
||||
EXPECT_CALL(bd_mock1, read(_, (SECTORS_NUM / 2 - 2) * BLOCK_SIZE, 2 * BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, 2*BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock2, read(_, 0, 2 * BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic+2*BLOCK_SIZE, 2*BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_EQ(bd.read(buf, (SECTORS_NUM / 2 - 2) * BLOCK_SIZE, 4 * BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(memcmp(magic, buf, BLOCK_SIZE * 4), 0);
|
||||
|
||||
|
||||
// erase
|
||||
EXPECT_CALL(bd_mock1, erase((SECTORS_NUM / 2 - 2) * BLOCK_SIZE, 2 * BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock2, erase(0, 2 * BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.erase((SECTORS_NUM / 2 - 2) * BLOCK_SIZE, 4 * BLOCK_SIZE), BD_ERROR_OK);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
../storage/blockdevice/source
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/ChainingBlockDevice.cpp
|
||||
../storage/blockdevice/source/HeapBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_ChainingBlockDevice.cpp
|
||||
)
|
||||
@@ -0,0 +1,135 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/ExhaustibleBlockDevice.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
#define ERASE_CYCLES (2)
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::ReturnArg;
|
||||
using ::testing::SaveArg;
|
||||
using ::testing::SaveArgPointee;
|
||||
using ::testing::SetArrayArgument;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::SetArgReferee;
|
||||
using ::testing::DoAll;
|
||||
|
||||
class ExhaustibleBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
ExhaustibleBlockDevice bd{&bd_mock, ERASE_CYCLES};
|
||||
uint8_t *magic;
|
||||
uint8_t *magic2;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
ON_CALL(bd_mock, size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_program_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_read_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
magic2 = new uint8_t[BLOCK_SIZE];
|
||||
buf = new uint8_t[BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
magic2[i] = 0xaa + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] magic2;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ExhaustibleBlockModuleTest, init)
|
||||
{
|
||||
ExhaustibleBlockDevice b(&bd_mock, ERASE_CYCLES);
|
||||
EXPECT_EQ(b.get_erase_size(), 0);
|
||||
EXPECT_EQ(b.get_erase_size(0), 0);
|
||||
EXPECT_EQ(b.get_erase_value(), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.get_read_size(), 0);
|
||||
EXPECT_EQ(b.get_program_size(), 0);
|
||||
EXPECT_EQ(b.size(), 0);
|
||||
EXPECT_EQ(b.erase(0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.program(magic, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.read(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.deinit(), BD_ERROR_OK);
|
||||
EXPECT_EQ(b.sync(), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_EQ(b.init(), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, get_type()).WillOnce(Return("mytype"));
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
|
||||
EXPECT_EQ(b.get_erase_size(), bd_mock.get_erase_size());
|
||||
EXPECT_EQ(b.get_erase_size(0), bd_mock.get_erase_size(0));
|
||||
EXPECT_EQ(b.get_erase_value(), bd_mock.get_erase_value());
|
||||
EXPECT_EQ(b.get_program_size(), 512);
|
||||
EXPECT_EQ(b.get_read_size(), 512);
|
||||
EXPECT_EQ(b.size(), bd_mock.size());
|
||||
EXPECT_EQ(b.get_type(), "mytype");
|
||||
EXPECT_EQ(b.deinit(), 0);
|
||||
}
|
||||
|
||||
TEST_F(ExhaustibleBlockModuleTest, program_unaligned)
|
||||
{
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(ExhaustibleBlockModuleTest, erase_cycle_limit_reached)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, program(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(ERASE_CYCLES - 1) // Will fall silently after erase cycles are worn out.
|
||||
.WillRepeatedly(Return(BD_ERROR_OK));
|
||||
|
||||
for (int i = 0; i < ERASE_CYCLES; i++) {
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
}
|
||||
|
||||
// Erase silently fails, no error report.
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(bd.program(magic2, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
}
|
||||
|
||||
TEST_F(ExhaustibleBlockModuleTest, erase_invalid)
|
||||
{
|
||||
ASSERT_GT(ERASE_CYCLES, 1);
|
||||
|
||||
// Unaligned erase should fail
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/ExhaustibleBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_ExhaustibleBlockDevice.cpp
|
||||
)
|
||||
@@ -0,0 +1,166 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/FlashSimBlockDevice.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
#define ERASE_VALUE (2)
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::ReturnArg;
|
||||
using ::testing::SaveArg;
|
||||
using ::testing::SaveArgPointee;
|
||||
using ::testing::SetArrayArgument;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::SetArgReferee;
|
||||
using ::testing::DoAll;
|
||||
|
||||
class FlashSimBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
FlashSimBlockDevice bd{&bd_mock, ERASE_VALUE};
|
||||
uint8_t *magic;
|
||||
uint8_t *magic2;
|
||||
uint8_t *erased_mem;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
ON_CALL(bd_mock, size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_program_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_read_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
magic2 = new uint8_t[BLOCK_SIZE];
|
||||
erased_mem = new uint8_t[BLOCK_SIZE];
|
||||
buf = new uint8_t[BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
magic2[i] = 0xaa + i + 1;
|
||||
erased_mem[i] = ERASE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] magic2;
|
||||
delete[] erased_mem;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FlashSimBlockModuleTest, init)
|
||||
{
|
||||
FlashSimBlockDevice b(&bd_mock, ERASE_VALUE);
|
||||
EXPECT_EQ(b.get_erase_size(), 0);
|
||||
EXPECT_EQ(b.get_erase_size(0), 0);
|
||||
EXPECT_EQ(b.get_read_size(), 0);
|
||||
EXPECT_EQ(b.get_program_size(), 0);
|
||||
EXPECT_EQ(b.size(), 0);
|
||||
EXPECT_EQ(b.erase(0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.program(magic, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.read(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.deinit(), BD_ERROR_OK);
|
||||
EXPECT_EQ(b.sync(), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_EQ(b.init(), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, get_type()).WillOnce(Return("mytype"));
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
|
||||
EXPECT_EQ(b.get_erase_size(), bd_mock.get_erase_size());
|
||||
EXPECT_EQ(b.get_erase_size(0), bd_mock.get_erase_size(0));
|
||||
EXPECT_EQ(b.get_erase_value(), ERASE_VALUE);
|
||||
EXPECT_EQ(b.get_program_size(), 512);
|
||||
EXPECT_EQ(b.get_read_size(), 512);
|
||||
EXPECT_EQ(b.size(), bd_mock.size());
|
||||
EXPECT_EQ(b.get_type(), "mytype");
|
||||
EXPECT_EQ(b.sync(), 0);
|
||||
EXPECT_EQ(b.deinit(), 0);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(FlashSimBlockModuleTest, program_unaligned)
|
||||
{
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(FlashSimBlockModuleTest, program_no_erase)
|
||||
{
|
||||
// Data has not been erased, so this fails
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), mbed::BD_ERROR_NOT_ERASED);
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(erased_mem, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(magic, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
// No program() call should happen for this call.
|
||||
EXPECT_EQ(bd.program(magic2, 0, BLOCK_SIZE), mbed::BD_ERROR_NOT_ERASED);
|
||||
}
|
||||
|
||||
TEST_F(FlashSimBlockModuleTest, reprogram)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(erased_mem, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(magic, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
|
||||
// Programming the same data.
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(erased_mem, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
}
|
||||
|
||||
TEST_F(FlashSimBlockModuleTest, erase_invalid)
|
||||
{
|
||||
// Unaligned erase should fail
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/FlashSimBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_FlashSimBlockDevice.cpp
|
||||
)
|
||||
@@ -0,0 +1,126 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/HeapBlockDevice.h"
|
||||
#include <string.h>
|
||||
#include "mbed_assert.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
|
||||
class HeapBlockDeviceTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp()
|
||||
{
|
||||
bd.init();
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
bd.deinit();
|
||||
}
|
||||
|
||||
mbed::HeapBlockDevice bd{DEVICE_SIZE};
|
||||
};
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, constructor)
|
||||
{
|
||||
// HeapBlockDevice(bd_size_t size, bd_size_t read, bd_size_t program, bd_size_t erase);
|
||||
mbed::HeapBlockDevice one{3000, 100, 200, 300};
|
||||
EXPECT_EQ(one.init(), BD_ERROR_OK);
|
||||
EXPECT_EQ(one.size(), 3000);
|
||||
EXPECT_EQ(one.get_read_size(), 100);
|
||||
EXPECT_EQ(one.get_program_size(), 200);
|
||||
EXPECT_EQ(one.get_erase_size(), 300);
|
||||
EXPECT_EQ(one.get_erase_size(0), 300);
|
||||
EXPECT_EQ(one.deinit(), BD_ERROR_OK);
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, constructor_wrong_size)
|
||||
{
|
||||
mbed_assert_throw_errors=true;
|
||||
ASSERT_ANY_THROW(mbed::HeapBlockDevice one(3050, 100));
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, double_init)
|
||||
{
|
||||
mbed::HeapBlockDevice one{DEVICE_SIZE};
|
||||
EXPECT_EQ(one.init(), BD_ERROR_OK);
|
||||
EXPECT_EQ(one.init(), BD_ERROR_OK);
|
||||
EXPECT_EQ(one.deinit(), BD_ERROR_OK); // First de-init does only decrement the counter
|
||||
EXPECT_EQ(one.deinit(), BD_ERROR_OK);
|
||||
EXPECT_EQ(one.deinit(), BD_ERROR_OK); //Third one does not de-init, but return immediately
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, get_type)
|
||||
{
|
||||
EXPECT_EQ(0, strcmp(bd.get_type(), "HEAP"));
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, erase_program_read)
|
||||
{
|
||||
uint8_t *block = new uint8_t[BLOCK_SIZE] {0xaa,0xbb,0xcc};
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE];
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(bd.program(block, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(0, memcmp(block, buf, BLOCK_SIZE));
|
||||
delete[] block;
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, use_uninitialized)
|
||||
{
|
||||
mbed::HeapBlockDevice one{DEVICE_SIZE};
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE];
|
||||
EXPECT_EQ(one.read(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(one.program(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, over_read)
|
||||
{
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE];
|
||||
EXPECT_EQ(bd.read(buf, DEVICE_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, over_write)
|
||||
{
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE] {0xaa,0xbb,0xcc};
|
||||
EXPECT_EQ(bd.program(buf, DEVICE_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, over_erase)
|
||||
{
|
||||
EXPECT_EQ(bd.erase(DEVICE_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, erase_uninitialized)
|
||||
{
|
||||
mbed::HeapBlockDevice one{DEVICE_SIZE};
|
||||
EXPECT_EQ(one.erase(DEVICE_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(HeapBlockDeviceTest, read_unprogrammed)
|
||||
{
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE];
|
||||
EXPECT_EQ(bd.read(buf, DEVICE_SIZE - BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);
|
||||
// Ignore the content, it is now zero, but does not need to be.
|
||||
delete[] buf;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
../storage/blockdevice/include
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/HeapBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-flags
|
||||
-DMBED_CONF_FAT_CHAN_FFS_DBG=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_READONLY=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_MINIMIZE=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_STRFUNC=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_FIND=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_MKFS=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_FASTSEEK=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_EXPAND=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_CHMOD=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_LABEL=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_FORWARD=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_CODE_PAGE=437
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_LFN=3
|
||||
-DMBED_CONF_FAT_CHAN_FF_MAX_LFN=255
|
||||
-DMBED_CONF_FAT_CHAN_FF_LFN_UNICODE=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_LFN_BUF=255
|
||||
-DMBED_CONF_FAT_CHAN_FF_SFN_BUF=12
|
||||
-DMBED_CONF_FAT_CHAN_FF_STRF_ENCODE=3
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_RPATH=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_VOLUMES=4
|
||||
-DMBED_CONF_FAT_CHAN_FF_STR_VOLUME_ID=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_VOLUME_STRS=\"RAM\",\"NAND\",\"CF\",\"SD\",\"SD2\",\"USB\",\"USB2\",\"USB3\"
|
||||
-DMBED_CONF_FAT_CHAN_FF_MULTI_PARTITION=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_MIN_SS=512
|
||||
-DMBED_CONF_FAT_CHAN_FF_MAX_SS=4096
|
||||
-DMBED_CONF_FAT_CHAN_FF_USE_TRIM=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_NOFSINFO=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_TINY=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_EXFAT=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_HEAPBUF=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_NORTC=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_NORTC_MON=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_NORTC_MDAY=1
|
||||
-DMBED_CONF_FAT_CHAN_FF_NORTC_YEAR=2017
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_LOCK=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_REENTRANT=0
|
||||
-DMBED_CONF_FAT_CHAN_FF_FS_TIMEOUT=1000
|
||||
-DMBED_CONF_FAT_CHAN_FF_SYNC_t=HANDLE
|
||||
-DMBED_CONF_FAT_CHAN_FLUSH_ON_NEW_CLUSTER=0
|
||||
-DMBED_CONF_FAT_CHAN_FLUSH_ON_NEW_SECTOR=1
|
||||
)
|
||||
@@ -0,0 +1,309 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/MBRBlockDevice.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define PART_DESC_SIZE (16)
|
||||
#define PARTITIONS (4)
|
||||
#define MBR_SIZE (PARTITIONS * PART_DESC_SIZE + 2)
|
||||
#define SECTORS_NUM (20)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE * SECTORS_NUM)
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::DoAll;
|
||||
|
||||
class MBRBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
MBRBlockDevice bd{&bd_mock, PARTITIONS};
|
||||
uint8_t *magic;
|
||||
uint8_t *magic2;
|
||||
uint8_t *buf;
|
||||
uint8_t MBR[MBR_SIZE] = {
|
||||
// mba_entry 0
|
||||
0x00, // status
|
||||
0x00, 0x02, 0x00, // chs_start
|
||||
0x0C, // type (FAT32)
|
||||
0x00, 0x05, 0x00, // chs_stop
|
||||
0x01, 0x00, 0x00, 0x00, // lba_offset
|
||||
SECTORS_NUM/4-1, 0x00, 0x00, 0x00, // lba_size
|
||||
// mba_entry 1
|
||||
0x00, // status
|
||||
0x00, 0x06, 0x00, // chs_start
|
||||
0x0C, // type
|
||||
0x00, 0x0A, 0x00, // chs_stop
|
||||
SECTORS_NUM/4, 0x00, 0x00, 0x00, // lba_offset
|
||||
SECTORS_NUM/4, 0x00, 0x00, 0x00, // lba_size
|
||||
// mba_entry 2
|
||||
0x00, // status
|
||||
0x00, 0x0B, 0x00, // chs_start
|
||||
0x83, // type (Linux)
|
||||
0x00, 0x0F, 0x00, // chs_stop
|
||||
2*SECTORS_NUM/4, 0x00, 0x00, 0x00, // lba_offset
|
||||
SECTORS_NUM/4, 0x00, 0x00, 0x00, // lba_size
|
||||
// mba_entry 3
|
||||
0x00, // status
|
||||
0x00, 0x10, 0x00, // chs_start
|
||||
0x82, // type (Linux swap)
|
||||
0x00, 0x14, 0x00, // chs_stop
|
||||
3*SECTORS_NUM/4, 0x00, 0x00, 0x00, // lba_offset
|
||||
SECTORS_NUM/4, 0x00, 0x00, 0x00, // lba_size (in sectors)
|
||||
// signature
|
||||
0x55, // signature 0
|
||||
0xaa // signature 1
|
||||
};
|
||||
uint8_t MBRbuf[BLOCK_SIZE];
|
||||
virtual void SetUp()
|
||||
{
|
||||
memset(MBRbuf, 0, BLOCK_SIZE);
|
||||
memcpy(MBRbuf + (BLOCK_SIZE - MBR_SIZE), MBR, MBR_SIZE);
|
||||
|
||||
ON_CALL(bd_mock, size()).WillByDefault(Return(DEVICE_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_program_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_read_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, is_valid_erase(_, _)).WillByDefault(Return(true));
|
||||
ON_CALL(bd_mock, init()).WillByDefault(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
magic2 = new uint8_t[BLOCK_SIZE];
|
||||
buf = new uint8_t[BLOCK_SIZE];
|
||||
|
||||
ASSERT_EQ(bd.init(), BD_ERROR_OK);
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
magic2[i] = 0xaa + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] magic2;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MBRBlockModuleTest, init)
|
||||
{
|
||||
MBRBlockDevice b(&bd_mock, PARTITIONS);
|
||||
EXPECT_EQ(b.get_erase_size(), 0);
|
||||
EXPECT_EQ(b.get_erase_size(0), 0);
|
||||
EXPECT_EQ(b.get_erase_value(), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.get_read_size(), 0);
|
||||
EXPECT_EQ(b.get_program_size(), 0);
|
||||
EXPECT_EQ(b.size(), 0);
|
||||
EXPECT_EQ(b.erase(0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.program(magic, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.read(buf, 0, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(b.deinit(), BD_ERROR_OK);
|
||||
EXPECT_EQ(b.sync(), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_EQ(b.init(), 0);
|
||||
|
||||
EXPECT_CALL(bd_mock, get_type()).WillOnce(Return("mytype"));
|
||||
EXPECT_CALL(bd_mock, deinit());
|
||||
|
||||
EXPECT_EQ(b.get_erase_size(), bd_mock.get_erase_size());
|
||||
EXPECT_EQ(b.get_erase_size(0), bd_mock.get_erase_size(0));
|
||||
EXPECT_EQ(b.get_erase_value(), bd_mock.get_erase_value());
|
||||
EXPECT_EQ(b.get_program_size(), 512);
|
||||
EXPECT_EQ(b.get_read_size(), 512);
|
||||
EXPECT_EQ(b.get_partition_number(), PARTITIONS);
|
||||
EXPECT_EQ(b.get_partition_start(), 3*DEVICE_SIZE/4);
|
||||
EXPECT_EQ(b.get_partition_stop(), DEVICE_SIZE);
|
||||
EXPECT_EQ(b.get_partition_type(), 0x82);
|
||||
EXPECT_EQ(b.size(), DEVICE_SIZE/4);
|
||||
EXPECT_EQ(b.get_type(), "mytype");
|
||||
EXPECT_EQ(b.deinit(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MBRBlockModuleTest, init_incorrect_signature)
|
||||
{
|
||||
MBRbuf[BLOCK_SIZE - MBR_SIZE + 64] = 0x00;
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
MBRBlockDevice b(&bd_mock, PARTITIONS);
|
||||
EXPECT_EQ(b.init(), mbed::BD_ERROR_INVALID_MBR);
|
||||
MBRbuf[BLOCK_SIZE - MBR_SIZE + 64] = 0xaa;
|
||||
}
|
||||
|
||||
TEST_F(MBRBlockModuleTest, init_invalid_type)
|
||||
{
|
||||
MBRbuf[BLOCK_SIZE - MBR_SIZE + 4] = 0x05; // 0x05 is extended partition - not supported
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
MBRBlockDevice b(&bd_mock, 1);
|
||||
EXPECT_EQ(b.init(), mbed::BD_ERROR_INVALID_PARTITION);
|
||||
MBRbuf[BLOCK_SIZE - MBR_SIZE + 4] = 0x0C;
|
||||
}
|
||||
|
||||
TEST_F(MBRBlockModuleTest, init_invalid_status)
|
||||
{
|
||||
MBRbuf[BLOCK_SIZE - MBR_SIZE] = 0x01;
|
||||
|
||||
EXPECT_CALL(bd_mock, init());
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
MBRBlockDevice b(&bd_mock, 1);
|
||||
EXPECT_EQ(b.init(), mbed::BD_ERROR_INVALID_PARTITION);
|
||||
MBRbuf[BLOCK_SIZE - MBR_SIZE] = 0x00;
|
||||
}
|
||||
|
||||
TEST_F(MBRBlockModuleTest, program_unaligned)
|
||||
{
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(MBRBlockModuleTest, program_read_erase)
|
||||
{
|
||||
constexpr uint32_t partition_offset = BLOCK_SIZE * 3 * SECTORS_NUM / PARTITIONS;
|
||||
//Unalinged addressing is not allowed
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
EXPECT_EQ(bd.read(magic, 0, BLOCK_SIZE-1), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(magic, BLOCK_SIZE), partition_offset, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, partition_offset, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(magic, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(partition_offset, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
}
|
||||
|
||||
TEST_F(MBRBlockModuleTest, partitioning)
|
||||
{
|
||||
uint8_t MBRbuf2[BLOCK_SIZE];
|
||||
memset(MBRbuf2, 0xFF, BLOCK_SIZE);
|
||||
memset(MBRbuf2 + BLOCK_SIZE - MBR_SIZE, 0x0, MBR_SIZE);
|
||||
|
||||
|
||||
// Partition 1
|
||||
memcpy(MBRbuf2 + BLOCK_SIZE - MBR_SIZE, MBRbuf + BLOCK_SIZE - MBR_SIZE, PART_DESC_SIZE);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf2, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
MBRbuf2[BLOCK_SIZE - 2] = MBRbuf[BLOCK_SIZE - 2]; //0x55
|
||||
MBRbuf2[BLOCK_SIZE - 1] = MBRbuf[BLOCK_SIZE - 1]; //0xaa
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(MBRbuf2, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(MBRBlockDevice::partition(&bd_mock, 1, 0x0C, 0,
|
||||
(SECTORS_NUM / 4) * BLOCK_SIZE), 0);
|
||||
|
||||
|
||||
// Partition 2
|
||||
memcpy(MBRbuf2 + BLOCK_SIZE - MBR_SIZE + PART_DESC_SIZE,
|
||||
MBRbuf + BLOCK_SIZE - MBR_SIZE + PART_DESC_SIZE, PART_DESC_SIZE);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf2, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(MBRbuf2, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(MBRBlockDevice::partition(&bd_mock, 2, 0x0C, (SECTORS_NUM / 4) * BLOCK_SIZE,
|
||||
(SECTORS_NUM / 4) * BLOCK_SIZE * 2), 0);
|
||||
|
||||
|
||||
// Partition 3
|
||||
memcpy(MBRbuf2 + BLOCK_SIZE - MBR_SIZE + 2 * PART_DESC_SIZE,
|
||||
MBRbuf + BLOCK_SIZE - MBR_SIZE + 2 * PART_DESC_SIZE, PART_DESC_SIZE);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf2, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(MBRbuf2, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(MBRBlockDevice::partition(&bd_mock, 3, 0x83, (SECTORS_NUM / 4) * BLOCK_SIZE * 2,
|
||||
(SECTORS_NUM / 4) * BLOCK_SIZE * 3), 0);
|
||||
|
||||
// Partition 4
|
||||
memcpy(MBRbuf2 + BLOCK_SIZE - MBR_SIZE + 3 * PART_DESC_SIZE,
|
||||
MBRbuf + BLOCK_SIZE - MBR_SIZE + 3 * PART_DESC_SIZE, PART_DESC_SIZE);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArg0ToCharPtr(MBRbuf2, BLOCK_SIZE), Return(BD_ERROR_OK)));
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_CALL(bd_mock, program(ByteBufferMatcher(MBRbuf2, BLOCK_SIZE), 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(MBRBlockDevice::partition(&bd_mock, 4, 0x82, -(SECTORS_NUM / 4) * BLOCK_SIZE), 0);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/MBRBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_MBRBlockDevice.cpp
|
||||
)
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/ObservingBlockDevice.h"
|
||||
#include "blockdevice/ReadOnlyBlockDevice.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
|
||||
class ObservingBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
ObservingBlockDevice bd{&bd_mock};
|
||||
uint8_t *magic;
|
||||
static int cnt;
|
||||
virtual void SetUp()
|
||||
{
|
||||
cnt = 0;
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
}
|
||||
|
||||
static void bd_change(BlockDevice* bd) {
|
||||
cnt++;
|
||||
}
|
||||
};
|
||||
|
||||
int ObservingBlockModuleTest::cnt = 0;
|
||||
|
||||
TEST_F(ObservingBlockModuleTest, init)
|
||||
{
|
||||
EXPECT_EQ(bd.get_erase_size(), bd_mock.get_erase_size());
|
||||
EXPECT_EQ(bd.get_erase_size(0), bd_mock.get_erase_size(0));
|
||||
EXPECT_EQ(bd.get_erase_value(), bd_mock.get_erase_value());
|
||||
EXPECT_EQ(bd.get_program_size(), bd_mock.get_program_size());
|
||||
EXPECT_EQ(bd.get_read_size(), bd_mock.get_read_size());
|
||||
EXPECT_EQ(bd.size(), bd_mock.size());
|
||||
EXPECT_EQ(bd.get_type(), bd_mock.get_type());
|
||||
}
|
||||
|
||||
TEST_F(ObservingBlockModuleTest, program_erase_cb)
|
||||
{
|
||||
EXPECT_CALL(bd_mock, program(magic, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
bd.attach(this->bd_change);
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(cnt, 1);
|
||||
|
||||
EXPECT_CALL(bd_mock, erase(0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(cnt, 2);
|
||||
|
||||
EXPECT_CALL(bd_mock, read(_, 0, BLOCK_SIZE))
|
||||
.Times(1)
|
||||
.WillOnce(Return(BD_ERROR_OK));
|
||||
|
||||
uint8_t buf[BLOCK_SIZE];
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(cnt, 2); // Counter stays the same
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/ObservingBlockDevice.cpp
|
||||
../storage/blockdevice/source/ReadOnlyBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
stubs/mbed_error.c
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_ObservingBlockDevice.cpp
|
||||
stubs/BlockDevice_mock.h
|
||||
)
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
#include "blockdevice/ProfilingBlockDevice.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::DoAll;
|
||||
|
||||
class ProfilingBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
ProfilingBlockDevice bd{&bd_mock};
|
||||
uint8_t *magic;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
ON_CALL(bd_mock, size()).WillByDefault(Return(DEVICE_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_program_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_read_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, is_valid_erase(_, _)).WillByDefault(Return(true));
|
||||
ON_CALL(bd_mock, init()).WillByDefault(Return(BD_ERROR_OK));
|
||||
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
buf = new uint8_t[BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ProfilingBlockModuleTest, init)
|
||||
{
|
||||
EXPECT_EQ(bd.get_erase_size(), bd_mock.get_erase_size());
|
||||
EXPECT_EQ(bd.get_erase_size(0), bd_mock.get_erase_size(0));
|
||||
EXPECT_EQ(bd.get_erase_value(), bd_mock.get_erase_value());
|
||||
EXPECT_EQ(bd.get_program_size(), bd_mock.get_program_size());
|
||||
EXPECT_EQ(bd.get_read_size(), bd_mock.get_read_size());
|
||||
EXPECT_EQ(bd.size(), bd_mock.size());
|
||||
EXPECT_EQ(bd.get_type(), bd_mock.get_type());
|
||||
}
|
||||
|
||||
TEST_F(ProfilingBlockModuleTest, count) {
|
||||
EXPECT_EQ(bd.get_read_count(), 0);
|
||||
EXPECT_EQ(bd.get_program_count(), 0);
|
||||
EXPECT_EQ(bd.get_erase_count(), 0);
|
||||
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.sync(), 0); // Should not have any influence
|
||||
|
||||
EXPECT_EQ(bd.get_program_count(), BLOCK_SIZE);
|
||||
EXPECT_EQ(bd.get_read_count(), 2 * BLOCK_SIZE);
|
||||
EXPECT_EQ(bd.get_erase_count(), 3 * BLOCK_SIZE);
|
||||
|
||||
bd.reset();
|
||||
|
||||
EXPECT_EQ(bd.get_read_count(), 0);
|
||||
EXPECT_EQ(bd.get_program_count(), 0);
|
||||
EXPECT_EQ(bd.get_erase_count(), 0);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/ProfilingBlockDevice.cpp
|
||||
../storage/blockdevice/source/HeapBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_ProfilingBlockDevice.cpp
|
||||
stubs/mbed_error.c
|
||||
)
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "stubs/BlockDevice_mock.h"
|
||||
#include "blockdevice/ReadOnlyBlockDevice.h"
|
||||
#include "platform/mbed_error.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
using ::testing::DoAll;
|
||||
|
||||
class ReadOnlyBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
BlockDeviceMock bd_mock;
|
||||
ReadOnlyBlockDevice bd{&bd_mock};
|
||||
uint8_t *magic;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
ON_CALL(bd_mock, size()).WillByDefault(Return(DEVICE_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size(_)).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_erase_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_program_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, get_read_size()).WillByDefault(Return(BLOCK_SIZE));
|
||||
ON_CALL(bd_mock, is_valid_erase(_, _)).WillByDefault(Return(true));
|
||||
ON_CALL(bd_mock, init()).WillByDefault(Return(BD_ERROR_OK));
|
||||
|
||||
ASSERT_EQ(bd.init(), 0);
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
buf = new uint8_t[BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
ASSERT_EQ(bd.deinit(), 0);
|
||||
delete[] magic;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ReadOnlyBlockModuleTest, init)
|
||||
{
|
||||
EXPECT_EQ(bd.get_erase_size(), bd_mock.get_erase_size());
|
||||
EXPECT_EQ(bd.get_erase_size(0), bd_mock.get_erase_size(0));
|
||||
EXPECT_EQ(bd.get_erase_value(), bd_mock.get_erase_value());
|
||||
EXPECT_EQ(bd.get_program_size(), bd_mock.get_program_size());
|
||||
EXPECT_EQ(bd.get_read_size(), bd_mock.get_read_size());
|
||||
EXPECT_EQ(bd.size(), bd_mock.size());
|
||||
EXPECT_EQ(bd.get_type(), bd_mock.get_type());
|
||||
}
|
||||
|
||||
TEST_F(ReadOnlyBlockModuleTest, write_protection) {
|
||||
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE), MBED_ERROR_WRITE_PROTECTED);
|
||||
EXPECT_EQ(bd.erase(0, BLOCK_SIZE), MBED_ERROR_WRITE_PROTECTED);
|
||||
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
|
||||
EXPECT_EQ(bd.sync(), 0); // Should not have any influence
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/ReadOnlyBlockDevice.cpp
|
||||
../storage/blockdevice/source/HeapBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/test_ReadOnlyBlockDevice.cpp
|
||||
stubs/mbed_error.c
|
||||
)
|
||||
@@ -0,0 +1,220 @@
|
||||
/* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "blockdevice/HeapBlockDevice.h"
|
||||
#include "blockdevice/SlicingBlockDevice.h"
|
||||
|
||||
#define BLOCK_SIZE (512)
|
||||
#define DEVICE_SIZE (BLOCK_SIZE*10)
|
||||
|
||||
class VerifyBorders_HeapBlockDevice : public mbed::HeapBlockDevice {
|
||||
public:
|
||||
mutable bool borders_crossed;
|
||||
mutable bd_size_t lower_limit;
|
||||
mutable bd_size_t upper_limit;
|
||||
|
||||
VerifyBorders_HeapBlockDevice(bd_size_t size)
|
||||
: HeapBlockDevice(size)
|
||||
{
|
||||
borders_crossed = false;
|
||||
lower_limit = 0;
|
||||
upper_limit = size;
|
||||
}
|
||||
|
||||
virtual bool is_valid_read(bd_addr_t addr, bd_size_t size) const
|
||||
{
|
||||
borders_crossed |= addr < lower_limit;
|
||||
borders_crossed |= addr + size > upper_limit;
|
||||
return BlockDevice::is_valid_read(addr, size);
|
||||
}
|
||||
|
||||
virtual bool is_valid_program(bd_addr_t addr, bd_size_t size) const
|
||||
{
|
||||
borders_crossed |= addr < lower_limit;
|
||||
borders_crossed |= addr + size > upper_limit;
|
||||
return BlockDevice::is_valid_program(addr, size);
|
||||
}
|
||||
|
||||
virtual bool is_valid_erase(bd_addr_t addr, bd_size_t size) const
|
||||
{
|
||||
borders_crossed |= addr < lower_limit;
|
||||
borders_crossed |= addr + size > upper_limit;
|
||||
return BlockDevice::is_valid_erase(addr, size);
|
||||
}
|
||||
};
|
||||
|
||||
class SlicingBlockModuleTest : public testing::Test {
|
||||
protected:
|
||||
VerifyBorders_HeapBlockDevice bd{DEVICE_SIZE};
|
||||
uint8_t *magic;
|
||||
uint8_t *buf;
|
||||
virtual void SetUp()
|
||||
{
|
||||
bd.init();
|
||||
magic = new uint8_t[BLOCK_SIZE];
|
||||
buf = new uint8_t[BLOCK_SIZE];
|
||||
// Generate simple pattern to verify against
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
magic[i] = 0xaa + i;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
bd.deinit();
|
||||
delete[] magic;
|
||||
delete[] buf;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, constructor)
|
||||
{
|
||||
mbed::SlicingBlockDevice slice(&bd, 0, bd.size());
|
||||
EXPECT_EQ(slice.init(), BD_ERROR_OK);
|
||||
EXPECT_EQ(slice.get_read_size(), bd.get_read_size());
|
||||
EXPECT_EQ(slice.get_program_size(), bd.get_read_size());
|
||||
EXPECT_EQ(slice.get_erase_size(), bd.get_read_size());
|
||||
EXPECT_EQ(slice.get_erase_size(0), bd.get_read_size());
|
||||
EXPECT_EQ(slice.deinit(), BD_ERROR_OK);
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, slice_in_middle)
|
||||
{
|
||||
uint8_t *program = new uint8_t[BLOCK_SIZE] {0xbb,0xbb,0xbb};
|
||||
|
||||
//Write magic value to heap block before and after the space for slice
|
||||
bd.program(magic, 0, BLOCK_SIZE);
|
||||
bd.program(magic, BLOCK_SIZE * 3, BLOCK_SIZE);
|
||||
|
||||
bd.upper_limit = BLOCK_SIZE * 3;
|
||||
bd.lower_limit = BLOCK_SIZE;
|
||||
bd.borders_crossed = false;
|
||||
|
||||
//Skip first block, then create sclicing device, with size of 2 blocks
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
EXPECT_EQ(slice.init(), BD_ERROR_OK);
|
||||
EXPECT_EQ(BLOCK_SIZE * 2, slice.size());
|
||||
EXPECT_EQ(bd.borders_crossed, false);
|
||||
|
||||
//Program a test value
|
||||
EXPECT_EQ(slice.program(program, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(slice.program(program, BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(bd.borders_crossed, false);
|
||||
|
||||
//Verify that blocks before and after the slicing blocks are not touched
|
||||
bd.read(buf, 0, BLOCK_SIZE);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
|
||||
bd.read(buf, BLOCK_SIZE * 3, BLOCK_SIZE);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
|
||||
|
||||
delete[] program;
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, slice_at_the_end)
|
||||
{
|
||||
uint8_t *program = new uint8_t[BLOCK_SIZE] {0xbb,0xbb,0xbb};
|
||||
|
||||
//Write magic value to heap block before the space for slice
|
||||
// our bd is 10*BLOCK_SIZE, so sector 7
|
||||
bd.program(magic, BLOCK_SIZE * 7, BLOCK_SIZE);
|
||||
|
||||
//Screate sclicing device, with size of 2 blocks
|
||||
// Use negative index
|
||||
mbed::SlicingBlockDevice slice(&bd, -BLOCK_SIZE*2);
|
||||
EXPECT_EQ(slice.init(), BD_ERROR_OK);
|
||||
EXPECT_EQ(BLOCK_SIZE * 2, slice.size());
|
||||
|
||||
//Program a test value
|
||||
EXPECT_EQ(slice.program(program, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(slice.program(program, BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);
|
||||
|
||||
//Verify that blocks before and after the slicing blocks are not touched
|
||||
bd.read(buf, BLOCK_SIZE * 7, BLOCK_SIZE);
|
||||
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
|
||||
|
||||
delete[] program;
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, over_write)
|
||||
{
|
||||
uint8_t *program = new uint8_t[BLOCK_SIZE] {0xbb,0xbb,0xbb};
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE];
|
||||
|
||||
//Screate sclicing device, with size of 2 blocks
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
EXPECT_EQ(slice.init(), BD_ERROR_OK);
|
||||
|
||||
EXPECT_EQ(slice.program(program, 0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(slice.program(program, BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);
|
||||
|
||||
// Verify written value
|
||||
EXPECT_EQ(slice.read(buf, BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);
|
||||
EXPECT_EQ(0, memcmp(buf, program, BLOCK_SIZE));
|
||||
|
||||
//Program a test value to address that is one pass the device size
|
||||
EXPECT_EQ(slice.program(program, 2 * BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
|
||||
delete[] buf;
|
||||
delete[] program;
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, over_read)
|
||||
{
|
||||
uint8_t *buf = new uint8_t[BLOCK_SIZE];
|
||||
|
||||
//Screate sclicing device, with size of 2 blocks
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
EXPECT_EQ(slice.init(), BD_ERROR_OK);
|
||||
|
||||
//Try to read a block after the slice
|
||||
EXPECT_EQ(slice.read(buf, 2 * BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, get_type)
|
||||
{
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
EXPECT_EQ(bd.get_type(), slice.get_type());
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, get_erase_value)
|
||||
{
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
EXPECT_EQ(bd.get_erase_value(), slice.get_erase_value());
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, erase)
|
||||
{
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
EXPECT_EQ(slice.erase(0, BLOCK_SIZE), BD_ERROR_OK);
|
||||
// Erase one block after the slice
|
||||
EXPECT_EQ(slice.erase(2*BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, sync)
|
||||
{
|
||||
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
|
||||
// Just a pass through
|
||||
EXPECT_EQ(slice.sync(), 0);
|
||||
}
|
||||
|
||||
TEST_F(SlicingBlockModuleTest, too_big_to_init)
|
||||
{
|
||||
mbed::SlicingBlockDevice slice(&bd, 0, DEVICE_SIZE + BLOCK_SIZE);
|
||||
// Just a pass through
|
||||
EXPECT_EQ(slice.init(), BD_ERROR_DEVICE_ERROR);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
..
|
||||
)
|
||||
|
||||
set(unittest-sources
|
||||
../storage/blockdevice/source/SlicingBlockDevice.cpp
|
||||
../storage/blockdevice/source/HeapBlockDevice.cpp
|
||||
stubs/mbed_atomic_stub.c
|
||||
stubs/mbed_assert_stub.cpp
|
||||
)
|
||||
|
||||
set(unittest-test-sources
|
||||
${CMAKE_CURRENT_LIST_DIR}/moduletest.cpp
|
||||
)
|
||||
Reference in New Issue
Block a user