blob: 906d62abb52b85931c1d1e9db8c6037751e51b1e [file] [log] [blame]
//===-- DexIndexTests.cpp ----------------------------*- C++ -*-----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "index/dex/Iterator.h"
#include "index/dex/Token.h"
#include "index/dex/Trigram.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <string>
#include <vector>
namespace clang {
namespace clangd {
namespace dex {
using ::testing::ElementsAre;
TEST(DexIndexIterators, DocumentIterator) {
const PostingList L = {4, 7, 8, 20, 42, 100};
auto DocIterator = create(L);
EXPECT_EQ(DocIterator->peek(), 4U);
EXPECT_EQ(DocIterator->reachedEnd(), false);
DocIterator->advance();
EXPECT_EQ(DocIterator->peek(), 7U);
EXPECT_EQ(DocIterator->reachedEnd(), false);
DocIterator->advanceTo(20);
EXPECT_EQ(DocIterator->peek(), 20U);
EXPECT_EQ(DocIterator->reachedEnd(), false);
DocIterator->advanceTo(65);
EXPECT_EQ(DocIterator->peek(), 100U);
EXPECT_EQ(DocIterator->reachedEnd(), false);
DocIterator->advanceTo(420);
EXPECT_EQ(DocIterator->reachedEnd(), true);
}
TEST(DexIndexIterators, AndWithEmpty) {
const PostingList L0;
const PostingList L1 = {0, 5, 7, 10, 42, 320, 9000};
auto AndEmpty = createAnd(create(L0));
EXPECT_EQ(AndEmpty->reachedEnd(), true);
auto AndWithEmpty = createAnd(create(L0), create(L1));
EXPECT_EQ(AndWithEmpty->reachedEnd(), true);
EXPECT_THAT(consume(*AndWithEmpty), ElementsAre());
}
TEST(DexIndexIterators, AndTwoLists) {
const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
auto And = createAnd(create(L1), create(L0));
EXPECT_EQ(And->reachedEnd(), false);
EXPECT_THAT(consume(*And), ElementsAre(0U, 7U, 10U, 320U, 9000U));
And = createAnd(create(L0), create(L1));
And->advanceTo(0);
EXPECT_EQ(And->peek(), 0U);
And->advanceTo(5);
EXPECT_EQ(And->peek(), 7U);
And->advanceTo(10);
EXPECT_EQ(And->peek(), 10U);
And->advanceTo(42);
EXPECT_EQ(And->peek(), 320U);
And->advanceTo(8999);
EXPECT_EQ(And->peek(), 9000U);
And->advanceTo(9001);
}
TEST(DexIndexIterators, AndThreeLists) {
const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
const PostingList L2 = {1, 4, 7, 11, 30, 60, 320, 9000};
auto And = createAnd(create(L0), create(L1), create(L2));
EXPECT_EQ(And->peek(), 7U);
And->advanceTo(300);
EXPECT_EQ(And->peek(), 320U);
And->advanceTo(100000);
EXPECT_EQ(And->reachedEnd(), true);
}
TEST(DexIndexIterators, OrWithEmpty) {
const PostingList L0;
const PostingList L1 = {0, 5, 7, 10, 42, 320, 9000};
auto OrEmpty = createOr(create(L0));
EXPECT_EQ(OrEmpty->reachedEnd(), true);
auto OrWithEmpty = createOr(create(L0), create(L1));
EXPECT_EQ(OrWithEmpty->reachedEnd(), false);
EXPECT_THAT(consume(*OrWithEmpty),
ElementsAre(0U, 5U, 7U, 10U, 42U, 320U, 9000U));
}
TEST(DexIndexIterators, OrTwoLists) {
const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
auto Or = createOr(create(L0), create(L1));
EXPECT_EQ(Or->reachedEnd(), false);
EXPECT_EQ(Or->peek(), 0U);
Or->advance();
EXPECT_EQ(Or->peek(), 4U);
Or->advance();
EXPECT_EQ(Or->peek(), 5U);
Or->advance();
EXPECT_EQ(Or->peek(), 7U);
Or->advance();
EXPECT_EQ(Or->peek(), 10U);
Or->advance();
EXPECT_EQ(Or->peek(), 30U);
Or->advanceTo(42);
EXPECT_EQ(Or->peek(), 42U);
Or->advanceTo(300);
EXPECT_EQ(Or->peek(), 320U);
Or->advanceTo(9000);
EXPECT_EQ(Or->peek(), 9000U);
Or->advanceTo(9001);
EXPECT_EQ(Or->reachedEnd(), true);
Or = createOr(create(L0), create(L1));
EXPECT_THAT(consume(*Or),
ElementsAre(0U, 4U, 5U, 7U, 10U, 30U, 42U, 60U, 320U, 9000U));
}
TEST(DexIndexIterators, OrThreeLists) {
const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
const PostingList L2 = {1, 4, 7, 11, 30, 60, 320, 9000};
auto Or = createOr(create(L0), create(L1), create(L2));
EXPECT_EQ(Or->reachedEnd(), false);
EXPECT_EQ(Or->peek(), 0U);
Or->advance();
EXPECT_EQ(Or->peek(), 1U);
Or->advance();
EXPECT_EQ(Or->peek(), 4U);
Or->advanceTo(7);
Or->advanceTo(59);
EXPECT_EQ(Or->peek(), 60U);
Or->advanceTo(9001);
EXPECT_EQ(Or->reachedEnd(), true);
}
// FIXME(kbobyrev): The testcase below is similar to what is expected in real
// queries. It should be updated once new iterators (such as boosting, limiting,
// etc iterators) appear. However, it is not exhaustive and it would be
// beneficial to implement automatic generation of query trees for more
// comprehensive testing.
TEST(DexIndexIterators, QueryTree) {
// An example of more complicated query
//
// +-----------------+
// |And Iterator:1, 5|
// +--------+--------+
// |
// |
// +------------------------------------+
// | |
// | |
// +----------v----------+ +----------v---------+
// |And Iterator: 1, 5, 9| |Or Iterator: 0, 1, 5|
// +----------+----------+ +----------+---------+
// | |
// +------+-----+ +---------+-----------+
// | | | | |
// +-------v-----+ +----v-----+ +--v--+ +-V--+ +---v---+
// |1, 3, 5, 8, 9| |1, 5, 7, 9| |Empty| |0, 5| |0, 1, 5|
// +-------------+ +----------+ +-----+ +----+ +-------+
const PostingList L0 = {1, 3, 5, 8, 9};
const PostingList L1 = {1, 5, 7, 9};
const PostingList L2 = {0, 5};
const PostingList L3 = {0, 1, 5};
const PostingList L4;
// Root of the query tree: [1, 5]
auto Root = createAnd(
// Lower And Iterator: [1, 5, 9]
createAnd(create(L0), create(L1)),
// Lower Or Iterator: [0, 1, 5]
createOr(create(L2), create(L3), create(L4)));
EXPECT_EQ(Root->reachedEnd(), false);
EXPECT_EQ(Root->peek(), 1U);
Root->advanceTo(0);
// Advance multiple times. Shouldn't do anything.
Root->advanceTo(1);
Root->advanceTo(0);
EXPECT_EQ(Root->peek(), 1U);
Root->advance();
EXPECT_EQ(Root->peek(), 5U);
Root->advanceTo(5);
EXPECT_EQ(Root->peek(), 5U);
Root->advanceTo(9000);
EXPECT_EQ(Root->reachedEnd(), true);
}
TEST(DexIndexIterators, StringRepresentation) {
const PostingList L0 = {4, 7, 8, 20, 42, 100};
const PostingList L1 = {1, 3, 5, 8, 9};
const PostingList L2 = {1, 5, 7, 9};
const PostingList L3 = {0, 5};
const PostingList L4 = {0, 1, 5};
const PostingList L5;
EXPECT_EQ(llvm::to_string(*(create(L0))), "[4, 7, 8, 20, 42, 100]");
auto Nested = createAnd(createAnd(create(L1), create(L2)),
createOr(create(L3), create(L4), create(L5)));
EXPECT_EQ(llvm::to_string(*Nested),
"(& (& [1, 3, 5, 8, 9] [1, 5, 7, 9]) (| [0, 5] [0, 1, 5] []))");
}
testing::Matcher<std::vector<Token>>
trigramsAre(std::initializer_list<std::string> Trigrams) {
std::vector<Token> Tokens;
for (const auto &Symbols : Trigrams) {
Tokens.push_back(Token(Token::Kind::Trigram, Symbols));
}
return testing::UnorderedElementsAreArray(Tokens);
}
TEST(DexIndexTrigrams, IdentifierTrigrams) {
EXPECT_THAT(generateIdentifierTrigrams("X86"), trigramsAre({"x86"}));
EXPECT_THAT(generateIdentifierTrigrams("nl"), trigramsAre({}));
EXPECT_THAT(generateIdentifierTrigrams("clangd"),
trigramsAre({"cla", "lan", "ang", "ngd"}));
EXPECT_THAT(generateIdentifierTrigrams("abc_def"),
trigramsAre({"abc", "abd", "ade", "bcd", "bde", "cde", "def"}));
EXPECT_THAT(
generateIdentifierTrigrams("a_b_c_d_e_"),
trigramsAre({"abc", "abd", "acd", "ace", "bcd", "bce", "bde", "cde"}));
EXPECT_THAT(
generateIdentifierTrigrams("unique_ptr"),
trigramsAre({"uni", "unp", "upt", "niq", "nip", "npt", "iqu", "iqp",
"ipt", "que", "qup", "qpt", "uep", "ept", "ptr"}));
EXPECT_THAT(generateIdentifierTrigrams("TUDecl"),
trigramsAre({"tud", "tde", "ude", "dec", "ecl"}));
EXPECT_THAT(generateIdentifierTrigrams("IsOK"),
trigramsAre({"iso", "iok", "sok"}));
EXPECT_THAT(generateIdentifierTrigrams("abc_defGhij__klm"),
trigramsAre({
"abc", "abd", "abg", "ade", "adg", "adk", "agh", "agk", "bcd",
"bcg", "bde", "bdg", "bdk", "bgh", "bgk", "cde", "cdg", "cdk",
"cgh", "cgk", "def", "deg", "dek", "dgh", "dgk", "dkl", "efg",
"efk", "egh", "egk", "ekl", "fgh", "fgk", "fkl", "ghi", "ghk",
"gkl", "hij", "hik", "hkl", "ijk", "ikl", "jkl", "klm",
}));
}
TEST(DexIndexTrigrams, QueryTrigrams) {
EXPECT_THAT(generateQueryTrigrams("X86"), trigramsAre({"x86"}));
EXPECT_THAT(generateQueryTrigrams("nl"), trigramsAre({}));
EXPECT_THAT(generateQueryTrigrams("clangd"),
trigramsAre({"cla", "lan", "ang", "ngd"}));
EXPECT_THAT(generateQueryTrigrams("abc_def"),
trigramsAre({"abc", "bcd", "cde", "def"}));
EXPECT_THAT(generateQueryTrigrams("a_b_c_d_e_"),
trigramsAre({"abc", "bcd", "cde"}));
EXPECT_THAT(generateQueryTrigrams("unique_ptr"),
trigramsAre({"uni", "niq", "iqu", "que", "uep", "ept", "ptr"}));
EXPECT_THAT(generateQueryTrigrams("TUDecl"),
trigramsAre({"tud", "ude", "dec", "ecl"}));
EXPECT_THAT(generateQueryTrigrams("IsOK"), trigramsAre({"iso", "sok"}));
EXPECT_THAT(generateQueryTrigrams("abc_defGhij__klm"),
trigramsAre({"abc", "bcd", "cde", "def", "efg", "fgh", "ghi",
"hij", "ijk", "jkl", "klm"}));
}
} // namespace dex
} // namespace clangd
} // namespace clang