blob: 901c3186a471dc96a16df83a707faa7972cf958a [file] [log] [blame]
// Copyright 2021 Google LLC
//
// 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 "util.hpp"
#include <flasher/ops.hpp>
#include <cstddef>
#include <cstring>
#include <stdexcept>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace flasher
{
namespace ops
{
using testing::ElementsAre;
using testing::Return;
using testing::SizeIs;
class EraseTest : public OpTest<testing::StrictMock<MockOrFakeDevice>>
{};
TEST_F(EraseTest, ArgumentValidation)
{
EXPECT_THROW(erase(d, /*dev_offset=*/0, /*max_size=*/0, /*stride_size=*/0,
/*noread=*/false),
std::invalid_argument);
EXPECT_THROW(erase(d, /*dev_offset=*/16, /*max_size=*/0, /*stride_size=*/4,
/*noread=*/false),
std::invalid_argument);
erase(d, /*dev_offset=*/0, /*max_size=*/0, /*stride_size=*/4,
/*noread=*/false);
EXPECT_THROW(erase(d, /*dev_offset=*/0, /*max_size=*/0,
/*stride_size=*/0, /*noread=*/false),
std::invalid_argument);
}
TEST_F(EraseTest, NoReadUnalignedTiny)
{
testing::Sequence seq, seq2;
df.data[0] = 1_b;
df.data[3] = 3_b;
EXPECT_CALL(d, readAt(SizeIs(1), 0)).InSequence(seq);
EXPECT_CALL(d, readAt(SizeIs(1), 3)).InSequence(seq2);
EXPECT_CALL(d, eraseBlocks(0, 1)).InSequence(seq, seq2);
EXPECT_CALL(d, writeAt(ElementsAre(1_b), 0)).InSequence(seq);
EXPECT_CALL(d, writeAt(ElementsAre(3_b), 3)).InSequence(seq2);
erase(d, /*dev_offset=*/1, /*max_size=*/2, /*stride_size=*/8,
/*noread=*/true);
}
TEST_F(EraseTest, NoReadUnalignedMulti)
{
testing::Sequence seq, seq2;
df.data[0] = 1_b;
df.data[6] = 6_b;
df.data[7] = 7_b;
EXPECT_CALL(d, readAt(SizeIs(1), 0)).InSequence(seq);
EXPECT_CALL(d, eraseBlocks(0, 1)).InSequence(seq);
EXPECT_CALL(d, writeAt(ElementsAre(1_b), 0)).InSequence(seq);
EXPECT_CALL(d, readAt(SizeIs(2), 6)).InSequence(seq2);
EXPECT_CALL(d, eraseBlocks(1, 1)).InSequence(seq2);
EXPECT_CALL(d, writeAt(ElementsAre(6_b, 7_b), 6)).InSequence(seq2);
erase(d, /*dev_offset=*/1, /*max_size=*/5, /*stride_size=*/4,
/*noread=*/true);
}
TEST_F(EraseTest, NoRead)
{
EXPECT_CALL(d, eraseBlocks(1, 2));
erase(d, /*dev_offset=*/4, /*max_size=*/9, /*stride_size=*/8,
/*noread=*/true);
}
TEST_F(EraseTest, MisalignedStride)
{
EXPECT_CALL(d, eraseBlocks(0, 2));
EXPECT_CALL(d, eraseBlocks(2, 1));
erase(d, /*dev_offset=*/0, /*max_size=*/16, /*stride_size=*/5,
/*noread=*/true);
}
TEST_F(EraseTest, LongerStride)
{
EXPECT_CALL(d, eraseBlocks(0, 3));
erase(d, /*dev_offset=*/0, /*max_size=*/16, /*stride_size=*/16,
/*noread=*/true);
}
TEST_F(EraseTest, WithRead)
{
testing::Sequence seq;
df.data = {0xff_b, 0xff_b, 0xff_b, 0xff_b, 0_b, 0_b, 0_b, 0_b};
EXPECT_CALL(d, readAt(SizeIs(4), 0));
EXPECT_CALL(d, readAt(SizeIs(4), 4)).InSequence(seq);
EXPECT_CALL(d, eraseBlocks(1, 1)).InSequence(seq);
erase(d, /*dev_offset=*/0, /*max_size=*/8, /*stride_size=*/4,
/*noread=*/false);
}
TEST_F(EraseTest, WithReadUnalignedTiny)
{
testing::Sequence seq, seq2;
df.data = {1_b, 0_b, 0_b, 3_b};
EXPECT_CALL(d, readAt(SizeIs(4), 0)).InSequence(seq, seq2);
EXPECT_CALL(d, eraseBlocks(0, 1)).InSequence(seq, seq2);
EXPECT_CALL(d, writeAt(ElementsAre(1_b), 0)).InSequence(seq);
EXPECT_CALL(d, writeAt(ElementsAre(3_b), 3)).InSequence(seq2);
erase(d, /*dev_offset=*/1, /*max_size=*/2, /*stride_size=*/4,
/*noread=*/false);
}
TEST_F(EraseTest, WithReadUnalignedTinyNoErase)
{
df.data = {1_b, 0xff_b, 0xff_b, 3_b};
EXPECT_CALL(d, readAt(SizeIs(4), 0));
erase(d, /*dev_offset=*/1, /*max_size=*/2, /*stride_size=*/8,
/*noread=*/false);
}
TEST_F(EraseTest, WithReadUnalignedMulti)
{
testing::Sequence seq, seq2;
df.data = {1_b, 0_b, 0_b, 0_b, 0_b, 0_b, 6_b, 7_b};
EXPECT_CALL(d, readAt(SizeIs(4), 0)).InSequence(seq);
EXPECT_CALL(d, eraseBlocks(0, 1)).InSequence(seq);
EXPECT_CALL(d, writeAt(ElementsAre(1_b), 0)).InSequence(seq);
EXPECT_CALL(d, readAt(SizeIs(4), 4)).InSequence(seq2);
EXPECT_CALL(d, eraseBlocks(1, 1)).InSequence(seq2);
EXPECT_CALL(d, writeAt(ElementsAre(6_b, 7_b), 6)).InSequence(seq2);
erase(d, /*dev_offset=*/1, /*max_size=*/5, /*stride_size=*/4,
/*noread=*/false);
}
TEST_F(EraseTest, WithReadUnalignedMultiNoErase)
{
std::memset(df.data.data(), 0xff, df.data.size());
df.data[0] = 1_b;
df.data[10] = 6_b;
df.data[11] = 7_b;
EXPECT_CALL(d, readAt(SizeIs(4), 0));
EXPECT_CALL(d, readAt(SizeIs(4), 4));
EXPECT_CALL(d, readAt(SizeIs(4), 8));
erase(d, /*dev_offset=*/1, /*max_size=*/9, /*stride_size=*/4,
/*noread=*/false);
}
} // namespace ops
} // namespace flasher