// 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 <gtest/gtest.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "cras_alert.h"
namespace {
void callback1(void *arg, void *data);
void callback2(void *arg, void *data);
void prepare(struct cras_alert *alert);
struct cb_data_struct {
int data;
};
static int cb1_called = 0;
static cb_data_struct cb1_data;
static int cb2_called = 0;
static int cb2_set_pending = 0;
static int prepare_called = 0;
void ResetStub() {
cb1_called = 0;
cb2_called = 0;
cb2_set_pending = 0;
prepare_called = 0;
cb1_data.data = 0;
}
class Alert: public testing::Test {
protected:
virtual void SetUp() {
cb1_data.data = 0;
}
virtual void TearDown() {
}
};
TEST_F(Alert, OneCallback) {
struct cras_alert *alert = cras_alert_create(NULL, 0);
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
cras_alert_pending(alert);
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, cb1_called);
cras_alert_destroy(alert);
}
TEST_F(Alert, OneCallbackPost2Call1) {
struct cras_alert *alert = cras_alert_create(NULL, 0);
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
// Alert twice, callback should only be called once.
cras_alert_pending(alert);
cras_alert_pending(alert);
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, cb1_called);
cras_alert_destroy(alert);
}
TEST_F(Alert, OneCallbackWithData) {
struct cras_alert *alert = cras_alert_create(NULL, 0);
struct cb_data_struct data = {1};
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
cras_alert_pending_data(alert, (void *)&data, sizeof(struct cb_data_struct));
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, cb1_called);
EXPECT_EQ(1, cb1_data.data);
cras_alert_destroy(alert);
}
TEST_F(Alert, OneCallbackTwoDataCalledOnce) {
struct cras_alert *alert = cras_alert_create(NULL, 0);
struct cb_data_struct data = {1};
struct cb_data_struct data2 = {2};
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
// Callback called with last data only.
cras_alert_pending_data(
alert, (void *)&data, sizeof(struct cb_data_struct));
cras_alert_pending_data(
alert, (void *)&data2, sizeof(struct cb_data_struct));
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, cb1_called);
EXPECT_EQ(2, cb1_data.data);
cras_alert_destroy(alert);
}
TEST_F(Alert, OneCallbackTwoDataKeepAll) {
struct cras_alert *alert = cras_alert_create(
NULL, CRAS_ALERT_FLAG_KEEP_ALL_DATA);
struct cb_data_struct data = {1};
struct cb_data_struct data2 = {2};
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
// Callbacks with data should each be called.
cras_alert_pending_data(alert, (void *)&data, sizeof(cb_data_struct));
cras_alert_pending_data(alert, (void *)&data2, sizeof(cb_data_struct));
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(2, cb1_called);
EXPECT_EQ(2, cb1_data.data);
cras_alert_destroy(alert);
}
TEST_F(Alert, TwoCallbacks) {
struct cras_alert *alert = cras_alert_create(NULL, 0);
cras_alert_add_callback(alert, &callback1, NULL);
cras_alert_add_callback(alert, &callback2, NULL);
ResetStub();
cras_alert_pending(alert);
EXPECT_EQ(0, cb1_called);
EXPECT_EQ(0, cb2_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, cb1_called);
EXPECT_EQ(1, cb2_called);
cras_alert_destroy(alert);
}
TEST_F(Alert, NoPending) {
struct cras_alert *alert = cras_alert_create(NULL, 0);
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(0, cb1_called);
cras_alert_destroy(alert);
}
TEST_F(Alert, PendingInCallback) {
struct cras_alert *alert1 = cras_alert_create(NULL, 0);
struct cras_alert *alert2 = cras_alert_create(NULL, 0);
cras_alert_add_callback(alert1, &callback1, NULL);
cras_alert_add_callback(alert2, &callback2, alert1);
ResetStub();
cras_alert_pending(alert2);
EXPECT_EQ(0, cb1_called);
EXPECT_EQ(0, cb2_called);
cb2_set_pending = 1;
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, cb1_called);
EXPECT_EQ(1, cb2_called);
cras_alert_destroy(alert1);
cras_alert_destroy(alert2);
}
TEST_F(Alert, Prepare) {
struct cras_alert *alert = cras_alert_create(prepare, 0);
cras_alert_add_callback(alert, &callback1, NULL);
ResetStub();
cras_alert_pending(alert);
EXPECT_EQ(0, cb1_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, prepare_called);
EXPECT_EQ(1, cb1_called);
cras_alert_destroy(alert);
}
TEST_F(Alert, TwoAlerts) {
struct cras_alert *alert1 = cras_alert_create(prepare, 0);
struct cras_alert *alert2 = cras_alert_create(prepare, 0);
cras_alert_add_callback(alert1, &callback1, NULL);
cras_alert_add_callback(alert2, &callback2, NULL);
ResetStub();
cras_alert_pending(alert1);
EXPECT_EQ(0, cb1_called);
EXPECT_EQ(0, cb2_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, prepare_called);
EXPECT_EQ(1, cb1_called);
EXPECT_EQ(0, cb2_called);
ResetStub();
cras_alert_pending(alert2);
EXPECT_EQ(0, cb1_called);
EXPECT_EQ(0, cb2_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(1, prepare_called);
EXPECT_EQ(0, cb1_called);
EXPECT_EQ(1, cb2_called);
ResetStub();
cras_alert_pending(alert1);
cras_alert_pending(alert2);
EXPECT_EQ(0, cb1_called);
EXPECT_EQ(0, cb2_called);
cras_alert_process_all_pending_alerts();
EXPECT_EQ(2, prepare_called);
EXPECT_EQ(1, cb1_called);
EXPECT_EQ(1, cb2_called);
cras_alert_destroy_all();
}
void callback1(void *arg, void *data)
{
cb1_called++;
if(data)
cb1_data.data = ((struct cb_data_struct *)data)->data;
}
void callback2(void *arg, void *data)
{
cb2_called++;
if (cb2_set_pending) {
cb2_set_pending = 0;
cras_alert_pending((struct cras_alert *)arg);
}
}
void prepare(struct cras_alert *alert)
{
prepare_called++;
return;
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}