blob: a92c476eb9e15d40d7d296e36ffa890d140ebfc0 [file] [log] [blame]
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "p2p/common/struct_serializer.h"
#include "p2p/common/testutil.h"
#include <fcntl.h>
#include <glib.h>
#include <unistd.h>
#include <string>
#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
using p2p::testutil::RunGMainLoopMaxIterations;
using std::string;
namespace {
struct TestStruct {
int a, b, c;
};
bool operator==(const TestStruct& left, const TestStruct& right) {
return left.a == right.a && left.b == right.b && left.c == right.c;
}
class TestStructCalls {
public:
TestStructCalls() : num_calls(0) {}
static void CountCalls(const TestStruct& data, void* user_data) {
TestStructCalls* calls = reinterpret_cast<TestStructCalls*>(user_data);
calls->num_calls++;
calls->last_call = data;
}
TestStruct last_call;
int num_calls;
};
bool SetupPipes(int fds[2]) {
if (pipe(fds) != 0) return false;
// Set the reading end as non-blocking.
int flags = fcntl(fds[0], F_GETFL, 0);
fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
return true;
}
} // namespace
namespace p2p {
namespace util {
TEST(StructSerializer, SimpleWriteTest) {
int fds[2];
ASSERT_TRUE(SetupPipes(fds));
const TestStruct sample = {1, 2, 3};
char buffer[sizeof(TestStruct)];
EXPECT_TRUE(StructSerializerWrite<TestStruct>(fds[1], sample));
EXPECT_EQ(sizeof(TestStruct), read(fds[0], buffer, sizeof(TestStruct)));
EXPECT_EQ(0, memcmp(&sample, buffer, sizeof(TestStruct)));
close(fds[0]);
close(fds[1]);
}
TEST(StructSerializer, WatchSeveralMessages) {
int fds[2];
ASSERT_TRUE(SetupPipes(fds));
TestStructCalls calls = TestStructCalls();
StructSerializerWatcher<TestStruct> watch(
fds[0], TestStructCalls::CountCalls, &calls);
TestStruct sample = {1, 2, 3};
EXPECT_TRUE(StructSerializerWrite<TestStruct>(fds[1], sample));
sample.b = 4;
EXPECT_TRUE(StructSerializerWrite<TestStruct>(fds[1], sample));
sample.c = 5;
EXPECT_TRUE(StructSerializerWrite<TestStruct>(fds[1], sample));
// Run the main loop until all the events are dispatched.
while (g_main_context_iteration(NULL, FALSE)) {}
EXPECT_EQ(calls.num_calls, 3);
const TestStruct result = {1, 4, 5};
EXPECT_EQ(calls.last_call, result);
close(fds[0]);
close(fds[1]);
}
TEST(StructSerializer, WatchNoMessages) {
int fds[2];
ASSERT_TRUE(SetupPipes(fds));
TestStructCalls calls = TestStructCalls();
StructSerializerWatcher<TestStruct> watch(
fds[0], TestStructCalls::CountCalls, &calls);
// Close the write end.
close(fds[1]);
// Run the main loop until all the events are dispatched.
int iterations = RunGMainLoopMaxIterations(10);
// No call is received but the callback is called once due to the hangup.
EXPECT_EQ(iterations, 1);
EXPECT_EQ(calls.num_calls, 0);
close(fds[0]);
}
TEST(StructSerializer, WatchPartialMessage) {
int fds[2];
ASSERT_TRUE(SetupPipes(fds));
TestStructCalls calls = TestStructCalls();
StructSerializerWatcher<TestStruct> watch(
fds[0], TestStructCalls::CountCalls, &calls);
// Write a partial message.
int x = -1;
ASSERT_EQ(sizeof(int), write(fds[1], &x, sizeof(x)));
// Run the main loop until all the events are dispatched.
int iterations = RunGMainLoopMaxIterations(10);
EXPECT_EQ(iterations, 1);
// Write the second part of the message.
x = 2;
ASSERT_EQ(sizeof(int), write(fds[1], &x, sizeof(x)));
x = 4;
ASSERT_EQ(sizeof(int), write(fds[1], &x, sizeof(x)));
iterations = RunGMainLoopMaxIterations(10);
EXPECT_EQ(iterations, 1);
EXPECT_EQ(calls.num_calls, 1);
const TestStruct result = {-1, 2, 4};
EXPECT_EQ(calls.last_call, result);
close(fds[0]);
close(fds[1]);
}
} // namespace util
} // namespace p2p