// ----------------------------------------------------------------------
// File: misc.cc
// Author: Georgios Bitzes - CERN
// ----------------------------------------------------------------------
/************************************************************************
* quarkdb - a redis-like highly available key-value store *
* Copyright (C) 2016 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include "storage/ReverseLocator.hh"
#include "storage/KeyLocators.hh"
#include
#include
using namespace quarkdb;
static char numToChar(int n) {
if(n == 0) {
return 'a';
}
else if(n == 1) {
return '#';
}
else if(n == 2) {
return '|';
}
return 'x';
}
void produceCombinations(std::vector &output, std::string ¤t, size_t pos) {
// Empty case
if(current.size() == 0) {
output.emplace_back("");
return;
}
// Base case, recursion is done
if(pos == current.size() - 1) {
for(size_t i = 0; i < 3; i++) {
current[pos] = numToChar(i);
output.emplace_back(current);
}
return;
}
// Recurse over all possible values for our pos
for(size_t i = 0; i < 3; i++) {
current[pos] = numToChar(i);
produceCombinations(output, current, pos+1);
}
}
std::vector produceCombinations(size_t length) {
std::vector output;
std::string current;
current.resize(length);
produceCombinations(output, current, 0);
return output;
}
TEST(ProduceCombinations, BasicSanity) {
std::vector combinations = produceCombinations(1);
ASSERT_EQ(combinations.size(), 3u);
ASSERT_EQ(combinations[0], "a");
ASSERT_EQ(combinations[1], "#");
ASSERT_EQ(combinations[2], "|");
combinations = produceCombinations(2);
ASSERT_EQ(combinations.size(), 9u);
ASSERT_EQ(combinations[0], "aa");
ASSERT_EQ(combinations[1], "a#");
ASSERT_EQ(combinations[2], "a|");
ASSERT_EQ(combinations[3], "#a");
ASSERT_EQ(combinations[4], "##");
ASSERT_EQ(combinations[5], "#|");
ASSERT_EQ(combinations[6], "|a");
ASSERT_EQ(combinations[7], "|#");
ASSERT_EQ(combinations[8], "||");
}
TEST(EscapedPrefixExtractor, BruteForceUpTo15) {
for(size_t length = 0; length < 15; length++) {
std::vector combinations = produceCombinations(length);
ASSERT_EQ(combinations.size(), pow(3, length));
for(size_t i = 0; i < combinations.size(); i++) {
std::string key = combinations[i];
FieldLocator locator(KeyType::kHash, key, "field");
std::string_view encoded = locator.toView();
encoded.remove_prefix(1);
EscapedPrefixExtractor extractor;
ASSERT_TRUE(extractor.parse(encoded));
ASSERT_EQ(extractor.getOriginalPrefix(), key);
ASSERT_EQ(extractor.getRawSuffix(), "field");
}
}
}
TEST(EscapedPrefixExtractor, BruteForce6CharCombinations) {
for(int c1 = 0; c1 < 3; c1++) {
for(int c2 = 0; c2 < 3; c2++) {
for(int c3 = 0; c3 < 3; c3++) {
for(int c4 = 0; c4 < 3; c4++) {
for(int c5 = 0; c5 < 3; c5++) {
for(int c6 = 0; c6 < 3; c6++) {
std::string key;
key.push_back(numToChar(c1));
key.push_back(numToChar(c2));
key.push_back(numToChar(c3));
key.push_back(numToChar(c4));
key.push_back(numToChar(c5));
key.push_back(numToChar(c6));
FieldLocator locator(KeyType::kHash, key, "field");
std::string_view encoded = locator.toView();
encoded.remove_prefix(1);
EscapedPrefixExtractor extractor;
ASSERT_TRUE(extractor.parse(encoded));
ASSERT_EQ(extractor.getOriginalPrefix(), key);
ASSERT_EQ(extractor.getRawSuffix(), "field");
}
}
}
}
}
}
}
TEST(EscapedPrefixExtractor, RandomizedTest) {
std::mt19937 generator(8888);
std::uniform_int_distribution<> lengthDistribution(0, 30);
std::uniform_int_distribution<> charDistribution(0, 2);
for(size_t round = 0; round < 5000000; round++) {
size_t keyLength = lengthDistribution(generator);
std::string key;
for(size_t i = 0; i < keyLength; i++) {
key.push_back(numToChar(charDistribution(generator)));
}
FieldLocator locator(KeyType::kHash, key, "field");
std::string_view encoded = locator.toView();
encoded.remove_prefix(1);
EscapedPrefixExtractor extractor;
ASSERT_TRUE(extractor.parse(encoded));
ASSERT_EQ(extractor.getOriginalPrefix(), key);
ASSERT_EQ(extractor.getRawSuffix(), "field");
}
}