mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
f31232d301
# Old Solver: - Fix a bug in the old solver where a user could use the keyword `typeof` as the name of a type alias. - Fix stringification of scientific notation to omit a trailing decimal place when not followed by a digit e.g. `1.e+20` -> `1e+20` # New Solver - Continuing work on the New non-strict mode - Introduce `keyof` and `rawkeyof` type function for acquiring the type of all keys in a table or class (https://github.com/luau-lang/rfcs/pull/16) --- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
597 lines
15 KiB
C++
597 lines
15 KiB
C++
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
#include "Luau/VecDeque.h"
|
|
|
|
#include "doctest.h"
|
|
|
|
TEST_SUITE_BEGIN("VecDequeTests");
|
|
|
|
TEST_CASE("forward_queue_test_no_initial_capacity")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<int> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(i);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 11);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), j);
|
|
CHECK_EQ(queue.back(), 9);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("forward_queue_test")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<int> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(i);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 13);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), j);
|
|
CHECK_EQ(queue.back(), 9);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("forward_queue_test_initializer_list")
|
|
{
|
|
Luau::VecDeque<int> queue{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), j);
|
|
CHECK_EQ(queue.back(), 9);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("reverse_queue_test")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<int> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_front(i);
|
|
// q: 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 13);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), 9);
|
|
CHECK_EQ(queue.back(), j);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_back();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("random_access_queue_test")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<int> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(i);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.at(j), j);
|
|
CHECK_EQ(queue[j], j);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("clear_works_on_queue")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<int> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(i);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], j);
|
|
|
|
queue.clear();
|
|
CHECK(queue.empty());
|
|
CHECK(queue.size() == 0);
|
|
}
|
|
|
|
TEST_CASE("pop_front_at_end")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<int> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
// setting up the internal buffer to be: 1234567890 by the end (i.e. 0 at the end of the buffer)
|
|
queue.push_front(0);
|
|
|
|
for (int i = 1; i < 10; i++)
|
|
queue.push_back(i);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), j);
|
|
CHECK_EQ(queue.back(), 9);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("pop_back_at_front")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<int> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
// setting up the internal buffer to be: 9012345678 by the end (i.e. 9 at the front of the buffer)
|
|
queue.push_back(0);
|
|
|
|
for (int i = 1; i < 10; i++)
|
|
queue.push_front(i);
|
|
// q: 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), 9);
|
|
CHECK_EQ(queue.back(), j);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_back();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("queue_is_contiguous")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<int> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(i);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 11);
|
|
CHECK(queue.is_contiguous());
|
|
}
|
|
|
|
TEST_CASE("queue_is_not_contiguous")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<int> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 5; i < 10; i++)
|
|
queue.push_back(i);
|
|
for (int i = 4; i >= 0; i--)
|
|
queue.push_front(i);
|
|
// buffer: 56789......01234
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 11);
|
|
CHECK(!queue.is_contiguous());
|
|
|
|
// checking that it is indeed sequential integers from 0 to 9
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], j);
|
|
}
|
|
|
|
TEST_CASE("shrink_to_fit_works")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<int> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 5; i < 10; i++)
|
|
queue.push_back(i);
|
|
for (int i = 4; i >= 0; i--)
|
|
queue.push_front(i);
|
|
// buffer: 56789......01234
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
REQUIRE_EQ(queue.capacity(), 11);
|
|
CHECK(!queue.is_contiguous());
|
|
|
|
// checking that it is indeed sequential integers from 0 to 9
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], j);
|
|
|
|
queue.shrink_to_fit();
|
|
// shrink to fit always makes a contiguous buffer
|
|
CHECK(queue.is_contiguous());
|
|
// the capacity should be exactly the size now
|
|
CHECK_EQ(queue.capacity(), queue.size());
|
|
|
|
REQUIRE(!queue.empty());
|
|
|
|
// checking that it is still sequential integers from 0 to 9
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], j);
|
|
}
|
|
|
|
// To avoid hitting SSO issues, we need sufficiently long strings.
|
|
// This list of test strings consists of quotes from Ursula K. Le Guin.
|
|
const static std::string testStrings[] = {
|
|
"Love doesn't just sit there, like a stone, it has to be made, like bread; remade all the time, made new.",
|
|
"People who deny the existence of dragons are often eaten by dragons. From within.",
|
|
"It is good to have an end to journey toward; but it is the journey that matters, in the end.",
|
|
"We're each of us alone, to be sure. What can you do but hold your hand out in the dark?",
|
|
"When you light a candle, you also cast a shadow.",
|
|
"You cannot buy the revolution. You cannot make the revolution. You can only be the revolution. It is in your spirit, or it is nowhere.",
|
|
"To learn which questions are unanswerable, and not to answer them: this skill is most needful in times of stress and darkness.",
|
|
"What sane person could live in this world and not be crazy?",
|
|
"The only thing that makes life possible is permanent, intolerable uncertainty: not knowing what comes next.",
|
|
"My imagination makes me human and makes me a fool; it gives me all the world and exiles me from it."
|
|
};
|
|
|
|
TEST_CASE("string_queue_test_no_initial_capacity")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<std::string> queue;
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 11);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), testStrings[j]);
|
|
CHECK_EQ(queue.back(), testStrings[9]);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("string_queue_test")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<std::string> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 13);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), testStrings[j]);
|
|
CHECK_EQ(queue.back(), testStrings[9]);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("string_queue_test_initializer_list")
|
|
{
|
|
Luau::VecDeque<std::string> queue{
|
|
testStrings[0],
|
|
testStrings[1],
|
|
testStrings[2],
|
|
testStrings[3],
|
|
testStrings[4],
|
|
testStrings[5],
|
|
testStrings[6],
|
|
testStrings[7],
|
|
testStrings[8],
|
|
testStrings[9],
|
|
};
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), testStrings[j]);
|
|
CHECK_EQ(queue.back(), testStrings[9]);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("reverse_string_queue_test")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<std::string> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_front(testStrings[i]);
|
|
// q: 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 13);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), testStrings[9]);
|
|
CHECK_EQ(queue.back(), testStrings[j]);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_back();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("random_access_string_queue_test")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<std::string> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.at(j), testStrings[j]);
|
|
CHECK_EQ(queue[j], testStrings[j]);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("clear_works_on_string_queue")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<std::string> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], testStrings[j]);
|
|
|
|
queue.clear();
|
|
CHECK(queue.empty());
|
|
CHECK(queue.size() == 0);
|
|
}
|
|
|
|
TEST_CASE("pop_front_string_at_end")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<std::string> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
// setting up the internal buffer to be: 1234567890 by the end (i.e. 0 at the end of the buffer)
|
|
queue.push_front(testStrings[0]);
|
|
|
|
for (int i = 1; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), testStrings[j]);
|
|
CHECK_EQ(queue.back(), testStrings[9]);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_front();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("pop_back_string_at_front")
|
|
{
|
|
// initial capacity set to 5 so that a grow is necessary
|
|
Luau::VecDeque<std::string> queue;
|
|
queue.reserve(5);
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
// setting up the internal buffer to be: 9012345678 by the end (i.e. 9 at the front of the buffer)
|
|
queue.push_back(testStrings[0]);
|
|
|
|
for (int i = 1; i < 10; i++)
|
|
queue.push_front(testStrings[i]);
|
|
// q: 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
CHECK_EQ(queue.front(), testStrings[9]);
|
|
CHECK_EQ(queue.back(), testStrings[j]);
|
|
|
|
REQUIRE(!queue.empty());
|
|
queue.pop_back();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("string_queue_is_contiguous")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<std::string> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 11);
|
|
CHECK(queue.is_contiguous());
|
|
}
|
|
|
|
TEST_CASE("string_queue_is_not_contiguous")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<std::string> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 5; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
for (int i = 4; i >= 0; i--)
|
|
queue.push_front(testStrings[i]);
|
|
// buffer: 56789......01234
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
CHECK_EQ(queue.capacity(), 11);
|
|
CHECK(!queue.is_contiguous());
|
|
|
|
// checking that it is indeed sequential integers from 0 to 9
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], testStrings[j]);
|
|
}
|
|
|
|
TEST_CASE("shrink_to_fit_works_with_strings")
|
|
{
|
|
// initial capacity is not set, so this should grow to be 11
|
|
Luau::VecDeque<std::string> queue{};
|
|
|
|
REQUIRE(queue.empty());
|
|
|
|
for (int i = 5; i < 10; i++)
|
|
queue.push_back(testStrings[i]);
|
|
for (int i = 4; i >= 0; i--)
|
|
queue.push_front(testStrings[i]);
|
|
// buffer: 56789......01234
|
|
// q: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
|
|
|
REQUIRE(!queue.empty());
|
|
REQUIRE(queue.size() == 10);
|
|
|
|
REQUIRE_EQ(queue.capacity(), 11);
|
|
CHECK(!queue.is_contiguous());
|
|
|
|
// checking that it is indeed sequential integers from 0 to 9
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], testStrings[j]);
|
|
|
|
queue.shrink_to_fit();
|
|
// shrink to fit always makes a contiguous buffer
|
|
CHECK(queue.is_contiguous());
|
|
// the capacity should be exactly the size now
|
|
CHECK_EQ(queue.capacity(), queue.size());
|
|
|
|
REQUIRE(!queue.empty());
|
|
|
|
// checking that it is still sequential integers from 0 to 9
|
|
for (int j = 0; j < 10; j++)
|
|
CHECK_EQ(queue[j], testStrings[j]);
|
|
}
|
|
|
|
TEST_SUITE_END();
|