blob: fd99cb08ed42cbc3726505291369cb20b32aa03e [file] [log] [blame]
// Copyright 2022 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.
//
// Tests hash map implementation, that will be used for LZW algorithm.
#include <algorithm>
#include <array>
#include <vector>
#include "src/utils/hash_map.h"
#include "tests/include/helpers.h"
namespace WP2 {
namespace {
Vector_s16 BuildTestData() {
constexpr std::array<int16_t, 20> data_array = {
0xFF, 0xF0, 0xF1, 0xF2, 0xFF, 0xF3, 0xF4, 0xF5, 0xFF, 0xF6,
0xF7, 0xF8, 0xFF, 0xF9, 0xFA, 0xFB, 0xFF, 0xFC, 0xFD, 0xFE,
};
Vector_s16 data;
if (data.resize(20)) {
std::copy(data_array.begin(), data_array.end(), data.begin());
}
return data;
}
// Build artificial 3x3 RGB square for testing.
WP2Status BuildArgbBuffer(WP2::ArgbBuffer& buf) {
WP2_CHECK_STATUS(buf.SetFormat(WP2_Argb_32));
constexpr uint32_t kSize = 3;
WP2_CHECK_STATUS(buf.Resize(kSize, kSize));
uint8_t color[4] = {0xFF, 0xFF, 0x00, 0x00};
buf.Fill({0, 0, 3, 1}, color);
color[2] = color[1];
color[1] = 0x00;
buf.Fill({0, 1, 3, 1}, color);
color[3] = color[2];
color[2] = 0x00;
buf.Fill({0, 2, 3, 1}, color);
return WP2_STATUS_OK;
}
// Tests if the hash map correctly adds a new segment.
TEST(LZWHashMap, InsertOneValue) {
Vector_s16 data;
ASSERT_TRUE(data.reserve(4));
data.push_back_no_resize(0xFF);
data.push_back_no_resize(0xF0);
data.push_back_no_resize(0xF1);
data.push_back_no_resize(0xF2);
constexpr uint32_t size = 3;
SegmentMap segment_map = SegmentMap(size);
ASSERT_WP2_OK(segment_map.Allocate());
uint32_t segment_index;
const ColorSegment segment = {&data[0], 1};
ASSERT_FALSE(segment_map.HasKey(segment, segment_index));
ASSERT_WP2_OK(segment_map.FindOrAdd(segment, segment_index));
ASSERT_TRUE(segment_map.HasKey(segment, segment_index));
}
// Tests if SegmentMap correctly adds until segments_ full.
TEST(LZWHashMap, InsertValuesUntilFull) {
constexpr uint32_t size = 3;
Vector_s16 data = BuildTestData();
SegmentMap segment_map = SegmentMap(size);
ASSERT_WP2_OK(segment_map.Allocate());
const std::vector<ColorSegment> segments = {
{&data[0], 1}, {&data[4], 1}, {&data[8], 2}};
uint32_t segment_index;
for (const ColorSegment& segment : segments) {
ASSERT_FALSE(segment_map.HasKey(segment, segment_index));
ASSERT_WP2_OK(segment_map.FindOrAdd(segment, segment_index));
ASSERT_TRUE(segment_map.HasKey(segment, segment_index));
}
for (const ColorSegment& segment : segments) {
ASSERT_TRUE(segment_map.HasKey(segment, segment_index));
}
// Clear cache and make sure segments are no longer found.
// Since "StartLZW" was not called, "num_colors_" wasn't defined, and
// every segment should be cleared.
segment_map.Clear();
for (const ColorSegment& segment : segments) {
ASSERT_FALSE(segment_map.HasKey(segment, segment_index));
}
}
// Tests if SegmentMap correctly fails to add when segments_ is full.
TEST(LZWHashMap, FailWhenFull) {
constexpr uint32_t size = 3;
Vector_s16 data = BuildTestData();
SegmentMap segment_map = SegmentMap(size);
ASSERT_WP2_OK(segment_map.Allocate());
const std::vector<ColorSegment> segments = {
{&data[0], 1}, {&data[4], 1}, {&data[8], 2}, {&data[16], 1}};
ColorSegment segment;
uint32_t segment_index;
for (uint32_t i = 0; i < 3; ++i) {
segment = segments[i];
ASSERT_FALSE(segment_map.HasKey(segment, segment_index));
ASSERT_WP2_OK(segment_map.FindOrAdd(segment, segment_index));
ASSERT_TRUE(segment_map.HasKey(segment, segment_index));
}
// Now try to insert another segment, it should fail.
segment = segments[3];
ASSERT_FALSE(segment_map.HasKey(segment, segment_index));
ASSERT_WP2_OK(segment_map.FindOrAdd(segment, segment_index));
ASSERT_EQ(segment_index, kClearCode);
ASSERT_FALSE(segment_map.HasKey(segment, segment_index));
}
// Tests if SegmentMap correctly inserts colors (1-pixel segments) from input.
TEST(LZWHashMap, InsertColors) {
ArgbBuffer simple_rgb_buf;
ASSERT_WP2_OK(BuildArgbBuffer(simple_rgb_buf));
WP2L::Palette palette;
palette.Init(WP2SampleFormat::WP2_Argb_32, true);
ASSERT_WP2_OK(palette.AnalyzeAndCreate(simple_rgb_buf));
constexpr uint32_t size = 10;
SegmentMap segment_map = SegmentMap(size);
ASSERT_WP2_OK(segment_map.Allocate());
ASSERT_WP2_OK(segment_map.InsertColors(palette));
constexpr int16_t kDataArray[] = {0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF};
const ColorSegment segments[] = {
{&kDataArray[0], 1}, {&kDataArray[4], 1}, {&kDataArray[8], 1}};
uint32_t segment_index;
for (const ColorSegment& segment : segments) {
ASSERT_TRUE(segment_map.HasKey(segment, segment_index));
}
}
} // namespace
} // namespace WP2