Import Mbed OS hard-float snapshot

This commit is contained in:
Beslan
2026-06-01 20:15:04 +03:00
commit d3738e2f89
16278 changed files with 10628036 additions and 0 deletions

View File

@@ -0,0 +1 @@
*

View File

@@ -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));
}

View File

@@ -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
)

View File

@@ -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);
}

View File

@@ -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
)

View File

@@ -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);
}

View File

@@ -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
)

View File

@@ -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);
}

View File

@@ -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
)

View File

@@ -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;
}

View File

@@ -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
)

View File

@@ -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);
}

View File

@@ -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
)

View File

@@ -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
}

View File

@@ -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
)

View File

@@ -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);
}

View File

@@ -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
)

View File

@@ -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
}

View File

@@ -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
)

View File

@@ -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);
}

View File

@@ -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
)