Skip to content

Commit

Permalink
libnixt/serialize: fixes serialize ExprSelect
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Dec 28, 2023
1 parent aca5657 commit 19fa773
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 52 deletions.
4 changes: 2 additions & 2 deletions libnixt/lib/Serialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class SerializeVisitor : public RecursiveASTVisitor<SerializeVisitor> {

std::size_t writeAttrName(const nix::AttrName &AN) {
std::size_t Ret = writeSymbol(AN.symbol);
write(OS, write(OS, ExprMap[AN.expr]));
write(OS, ExprMap[AN.expr]);
return Ret;
}

Expand Down Expand Up @@ -137,7 +137,7 @@ class SerializeVisitor : public RecursiveASTVisitor<SerializeVisitor> {
bool visitExprSelect(const nix::ExprSelect *E) {
assert(E);
ExprMap[E] = write(OS, ExprKind::ExprSelect);
write(OS, writePosIdx(E->pos));
writePosIdx(E->pos);
write(OS, ExprMap[E->def]);
write(OS, ExprMap[E->e]);
writeAttrPath(E->attrPath);
Expand Down
144 changes: 94 additions & 50 deletions libnixt/test/Serialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <bit>
#include <string_view>
#include <type_traits>

using namespace nixt::serialize;
using namespace std::literals;
Expand All @@ -19,6 +20,7 @@ class SerializeTest : public testing::Test {
nix::PosTable PT;
nix::SymbolTable ST;
std::ostringstream OS;

std::string write(const nix::Expr *E) {
nixt::serialize::write(OS, ST, PT, E);
return OS.str();
Expand All @@ -30,78 +32,105 @@ class SerializeTest : public testing::Test {
nix::AttrName someAttrName() { return {ST.create("hello")}; }
};

std::unique_ptr<nix::ExprInt> mkInt() {
return std::make_unique<nix::ExprInt>(0xdeadbeef);
std::unique_ptr<nix::ExprInt> mkInt(nix::NixInt N) {
return std::make_unique<nix::ExprInt>(N);
}

std::size_t checkASTHeader(std::string_view Str) {
std::string_view checkASTHeader(std::string_view Str) {
ASTHeader Header;
assert(Str.size() >= sizeof(ASTHeader));
std::memcpy(&Header, Str.begin(), sizeof(ASTHeader));
EXPECT_EQ(std::memcmp(Header.Magic, "\x7FNixAST\0", 8), 0);
EXPECT_EQ(Header.Version, 1);
return sizeof(ASTHeader);
return Str.substr(sizeof(ASTHeader));
}

void check(std::string_view Str, std::string_view Expected) {
checkASTHeader(Str.substr(0, sizeof(ASTHeader)));
EXPECT_EQ(Str.substr(sizeof(ASTHeader)), Expected);
std::string_view checkExpected(std::string_view Str,
std::string_view Expected) {
assert(Str.size() >= Expected.size());
EXPECT_EQ(Str.substr(0, Expected.size()), Expected);
return Str.substr(Expected.size());
}

std::size_t checkKind(std::string_view Str, ExprKind Expected) {
ExprKind LHS;
assert(Str.size() >= sizeof(ExprKind));
std::memcpy(&LHS, Str.begin(), sizeof(ExprKind));
template <class T>
requires std::is_standard_layout_v<T> && std::is_trivial_v<T>
std::string_view checkPOD(std::string_view Str, T Expected) {
T LHS;
assert(Str.size() >= sizeof(T));
std::memcpy(&LHS, Str.begin(), sizeof(T));
EXPECT_EQ(LHS, Expected);
return sizeof(ExprKind);
return Str.substr(sizeof(T));
}

std::size_t checkSomeInt(std::string_view Str) {
std::string_view Expected = "\x6\0\0\0\xEF\xBE\xAD\xDE\0\0\0\0"sv;
assert(Str.size() >= Expected.size());
EXPECT_EQ(Str.substr(0, Expected.size()), Expected);
return Expected.size();
std::string_view checkExprInt(std::string_view Str, nix::NixInt N) {
Str = checkPOD(Str, ExprKind::ExprInt);
Str = checkPOD(Str, N);
return Str;
}

std::size_t checkSomePos(std::string_view Str) {
std::string_view Expected = "\x20\0\0\0" // E->pos, column
"\x20\0\0\0" // E->pos, column
"\0\0\0\0\0\0\0\0"sv; // origin.index() == 0
assert(Str.size() >= Expected.size());
EXPECT_EQ(Str.substr(0, Expected.size()), Expected);
return Expected.size();
std::string_view checkSomePos(std::string_view Str) {
Str = checkPOD(Str, 32);
Str = checkPOD(Str, 32);
Str = checkPOD(Str, 0L);
return Str;
}

TEST_F(SerializeTest, ExprInt) {
nix::ExprInt E(0x2adeadbeef);
std::string_view Expected = "\x6\0\0\0\xEF\xBE\xAD\xDE\x2A\0\0\0"sv;
check(write(&E), Expected);

std::string Data = write(&E);
std::string_view View = Data;

View = checkASTHeader(View);
View = checkExpected(View, Expected);

EXPECT_EQ(View.size(), 0);
}

TEST_F(SerializeTest, ExprFloat) {
union {
double D;
std::uint64_t U;
} Data;
Data.U = 0x2adeadbeef;
} Expr;
Expr.U = 0x2adeadbeef;

nix::ExprFloat E(Data.D);
nix::ExprFloat E(Expr.D);
std::string_view Expected = "\x4\0\0\0\xEF\xBE\xAD\xDE\x2A\0\0\0"sv;
check(write(&E), Expected);
std::string Data = write(&E);
std::string_view View = Data;

View = checkASTHeader(View);
View = checkExpected(View, Expected);

EXPECT_EQ(View.size(), 0);
}

TEST_F(SerializeTest, ExprString) {
nix::ExprString E("Hello World");
std::string_view Expected = "\x16\0\0\0"
"\0\0\0\0\0\0\0\0"sv;
check(write(&E), Expected);
std::string Data = write(&E);
std::string_view View = Data;

View = checkASTHeader(View);
View = checkExpected(View, Expected);

EXPECT_EQ(View.size(), 0);
}

TEST_F(SerializeTest, ExprPath) {
nix::ExprPath E("Hello World");
std::string_view Expected = "\x13\0\0\0"
"\0\0\0\0\0\0\0\0"sv;
check(write(&E), Expected);

std::string Data = write(&E);
std::string_view View = Data;

View = checkASTHeader(View);
View = checkExpected(View, Expected);

EXPECT_EQ(View.size(), 0);
}

TEST_F(SerializeTest, ExprVar) {
Expand All @@ -110,37 +139,52 @@ TEST_F(SerializeTest, ExprVar) {
E.fromWith = true;
E.level = 0xdeadbeef;
E.displ = 0xbeef5a5a;

std::string Data = write(&E);
std::string_view View = Data;

View = checkASTHeader(View);
View = checkPOD(View, ExprKind::ExprVar);
View = checkSomePos(View);

std::string_view Expected =
"\x17\0\0\0" // kind
"\x20\0\0\0" // E->pos, column
"\x20\0\0\0" // E->pos, column
"\0\0\0\0\0\0\0\0" // origin.index() == 0
"\0\0\0\0\0\0\0\0" // E->symbol, 5, length of "hello"
"\x01" // E->fromWidth
"\xEF\xBE\xAD\xDE" // E->level
"\x5A\x5A\xEF\xBE"sv; // E->displ
check(write(&E), Expected);

View = checkExpected(View, Expected);

EXPECT_EQ(View.size(), 0);
}

TEST_F(SerializeTest, ExprSelect) {
auto SubE = mkInt();
auto SubDef = mkInt();
nix::NixInt EInt = 0xdeadbeef;
nix::NixInt DefInt = 0xbeefdead;
auto SubE = mkInt(EInt);
auto SubDef = mkInt(DefInt);
nix::AttrPath Path{someAttrName()};
nix::ExprSelect E(somePos(), SubE.get(), std::move(Path), SubDef.get());
std::string Data = write(&E);
std::string_view View = Data;
std::size_t Base = 0;

Base += checkASTHeader(View);
Base += checkSomeInt(View.substr(Base));
Base += checkSomeInt(View.substr(Base));
Base += checkKind(View.substr(Base), ExprKind::ExprSelect);
Base += checkSomePos(View.substr(Base));

std::string_view Expected = "\x0c\0\0\0\0\0\0\0"
"\x18\0\0\0\0\0\0\0"sv;

EXPECT_EQ(View.substr(Base), Expected);
const char *ViewOriginBegin = View.begin();

View = checkASTHeader(View);
std::size_t DefLoc = View.begin() - ViewOriginBegin;
View = checkExprInt(View, DefInt);
std::size_t ELoc = View.begin() - ViewOriginBegin;
View = checkExprInt(View, EInt);
View = checkPOD(View, ExprKind::ExprSelect);
View = checkSomePos(View);
View = checkPOD(View, DefLoc); // E->def
View = checkPOD(View, ELoc); // E->e

// check attrpath
View = checkPOD(View, 1L);
View = checkPOD(View, 0L);
View = checkPOD(View, 0L);

EXPECT_EQ(View.size(), 0);
}

} // namespace

0 comments on commit 19fa773

Please sign in to comment.