[gbinder-radio] Added unit tests. JB#55524
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,6 +8,8 @@ debian/*.substvars
|
||||
debian/*.install
|
||||
debian/tmp
|
||||
documentation.list
|
||||
unit/coverage/*.gcov
|
||||
unit/coverage/report
|
||||
installroot
|
||||
build
|
||||
RPMS
|
||||
|
||||
16
Makefile
16
Makefile
@@ -1,7 +1,8 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: clean all debug release coverage
|
||||
.PHONY: clean all debug release coverage test
|
||||
.PHONY: debug_lib release_lib coverage_lib
|
||||
.PHONY: print_debug_lib print_release_lib print_coverage_lib
|
||||
.PHONY: pkgconfig install install-dev
|
||||
|
||||
|
||||
@@ -138,7 +139,17 @@ coverage_lib: $(COVERAGE_LIB)
|
||||
|
||||
pkgconfig: $(PKGCONFIG)
|
||||
|
||||
print_debug_lib:
|
||||
@echo $(DEBUG_LIB)
|
||||
|
||||
print_release_lib:
|
||||
@echo $(RELEASE_LIB)
|
||||
|
||||
print_coverage_lib:
|
||||
@echo $(COVERAGE_LIB)
|
||||
|
||||
clean:
|
||||
make -C unit clean
|
||||
rm -f *~ $(SRC_DIR)/*~ $(INCLUDE_DIR)/*~
|
||||
rm -fr $(BUILD_DIR) RPMS installroot
|
||||
rm -fr debian/tmp debian/libgbinder-radio debian/libgbinder-radio-dev
|
||||
@@ -146,6 +157,9 @@ clean:
|
||||
rm -f debian/*.debhelper.log debian/*.debhelper debian/*~
|
||||
rm -f debian/*.install
|
||||
|
||||
test:
|
||||
make -C unit test
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ URL: https://github.com/mer-hybris/libgbinder-radio
|
||||
Source: %{name}-%{version}.tar.bz2
|
||||
|
||||
%define libgbinder_version 1.0.9
|
||||
%define libglibutil_version 1.0.34
|
||||
|
||||
BuildRequires: pkgconfig(glib-2.0)
|
||||
BuildRequires: pkgconfig(libglibutil)
|
||||
BuildRequires: pkgconfig(libglibutil) >= %{libglibutil_version}
|
||||
BuildRequires: pkgconfig(libgbinder) >= %{libgbinder_version}
|
||||
Requires: libglibutil >= %{libglibutil_version}
|
||||
Requires: libgbinder >= %{libgbinder_version}
|
||||
Requires(post): /sbin/ldconfig
|
||||
Requires(postun): /sbin/ldconfig
|
||||
@@ -31,12 +33,15 @@ This package contains the development library for %{name}.
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
make LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
|
||||
make %{_smp_mflags} LIBDIR=%{_libdir} KEEP_SYMBOLS=1 release pkgconfig
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
make LIBDIR=%{_libdir} DESTDIR=%{buildroot} install-dev
|
||||
|
||||
%check
|
||||
make -C unit test
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
|
||||
%postun -p /sbin/ldconfig
|
||||
|
||||
11
unit/Makefile
Normal file
11
unit/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
all:
|
||||
%:
|
||||
@$(MAKE) -C unit_instance $*
|
||||
@$(MAKE) -C unit_registry $*
|
||||
@$(MAKE) -C unit_util $*
|
||||
|
||||
clean: unitclean
|
||||
rm -f coverage/*.gcov
|
||||
rm -fr coverage/report
|
||||
217
unit/common/Makefile
Normal file
217
unit/common/Makefile
Normal file
@@ -0,0 +1,217 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
.PHONY: clean all debug release coverage
|
||||
.PHONY: debug_lib release_lib coverage_lib
|
||||
|
||||
#
|
||||
# Real test makefile defines EXE (and possibly SRC) and includes this one.
|
||||
#
|
||||
|
||||
ifndef EXE
|
||||
${error EXE not defined}
|
||||
endif
|
||||
|
||||
SRC ?= $(EXE).c
|
||||
COMMON_SRC ?= \
|
||||
test_gbinder_client.c \
|
||||
test_gbinder_local_object.c \
|
||||
test_gbinder_local_request.c \
|
||||
test_gbinder_local_reply.c \
|
||||
test_gbinder_reader_writer.c \
|
||||
test_gbinder_remote_object.c \
|
||||
test_gbinder_remote_request.c \
|
||||
test_gbinder_remote_reply.c \
|
||||
test_gbinder_servicemanager.c \
|
||||
test_main.c
|
||||
|
||||
#
|
||||
# Required packages
|
||||
#
|
||||
|
||||
LINK_PKGS += libglibutil glib-2.0 gobject-2.0
|
||||
PKGS += $(LINK_PKGS) libgbinder
|
||||
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
all: debug release
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
SRC_DIR = .
|
||||
LIB_DIR = ../..
|
||||
COMMON_DIR = ../common
|
||||
BUILD_DIR = build
|
||||
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
|
||||
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
|
||||
COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
|
||||
COMMON_BUILD_DIR = $(COMMON_DIR)/build
|
||||
COMMON_DEBUG_BUILD_DIR = $(COMMON_BUILD_DIR)/debug
|
||||
COMMON_RELEASE_BUILD_DIR = $(COMMON_BUILD_DIR)/release
|
||||
COMMON_COVERAGE_BUILD_DIR = $(COMMON_BUILD_DIR)/coverage
|
||||
|
||||
#
|
||||
# Tools and flags
|
||||
#
|
||||
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
LD = $(CC)
|
||||
WARNINGS += -Wall -Wno-deprecated-declarations
|
||||
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
|
||||
BASE_FLAGS = -fPIC
|
||||
BASE_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
|
||||
BASE_CFLAGS = $(BASE_FLAGS) $(CFLAGS)
|
||||
FULL_CFLAGS = $(BASE_CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
|
||||
$(shell pkg-config --cflags $(PKGS))
|
||||
FULL_LDFLAGS = $(BASE_LDFLAGS)
|
||||
LIBS = $(shell pkg-config --libs $(LINK_PKGS)) -lpthread
|
||||
QUIET_MAKE = make --no-print-directory
|
||||
DEBUG_FLAGS = -g
|
||||
RELEASE_FLAGS =
|
||||
COVERAGE_FLAGS = -g
|
||||
|
||||
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
|
||||
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
|
||||
COVERAGE_LDFLAGS = $(FULL_LDFLAGS) $(COVERAGE_FLAGS) --coverage
|
||||
|
||||
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
|
||||
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
|
||||
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
|
||||
|
||||
DEBUG_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_lib)
|
||||
RELEASE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_lib)
|
||||
COVERAGE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_coverage_lib)
|
||||
|
||||
DEBUG_LIB = $(LIB_DIR)/$(DEBUG_LIB_FILE)
|
||||
RELEASE_LIB = $(LIB_DIR)/$(RELEASE_LIB_FILE)
|
||||
COVERAGE_LIB = $(LIB_DIR)/$(COVERAGE_LIB_FILE)
|
||||
|
||||
DEBUG_LIBS = $(DEBUG_LIB) $(LIBS)
|
||||
RELEASE_LIBS = $(RELEASE_LIB) $(LIBS)
|
||||
COVERAGE_LIBS = $(COVERAGE_LIB) $(LIBS)
|
||||
|
||||
#
|
||||
# Files
|
||||
#
|
||||
|
||||
TEST_DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
|
||||
TEST_RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
|
||||
TEST_COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
|
||||
COMMON_DEBUG_OBJS = $(COMMON_SRC:%.c=$(COMMON_DEBUG_BUILD_DIR)/%.o)
|
||||
COMMON_RELEASE_OBJS = $(COMMON_SRC:%.c=$(COMMON_RELEASE_BUILD_DIR)/%.o)
|
||||
COMMON_COVERAGE_OBJS = $(COMMON_SRC:%.c=$(COMMON_COVERAGE_BUILD_DIR)/%.o)
|
||||
DEBUG_OBJS = $(COMMON_DEBUG_OBJS) $(TEST_DEBUG_OBJS)
|
||||
RELEASE_OBJS = $(COMMON_RELEASE_OBJS) $(TEST_RELEASE_OBJS)
|
||||
COVERAGE_OBJS = $(COMMON_COVERAGE_OBJS) $(TEST_COVERAGE_OBJS)
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
|
||||
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(strip $(DEPS)),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
$(DEBUG_LIB): | debug_lib
|
||||
$(RELEASE_LIB): | release_lib
|
||||
$(COVERAGE_LIB): | coverage_lib
|
||||
|
||||
$(TEST_DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
|
||||
$(TEST_RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
|
||||
$(TEST_COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
|
||||
|
||||
$(COMMON_DEBUG_OBJS): | $(COMMON_DEBUG_BUILD_DIR)
|
||||
$(COMMON_RELEASE_OBJS): | $(COMMON_RELEASE_BUILD_DIR)
|
||||
$(COMMON_COVERAGE_OBJS): | $(COMMON_COVERAGE_BUILD_DIR)
|
||||
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
|
||||
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
|
||||
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
|
||||
COVERAGE_EXE = $(COVERAGE_BUILD_DIR)/$(EXE)
|
||||
|
||||
debug: debug_lib $(DEBUG_EXE)
|
||||
|
||||
release: release_lib $(RELEASE_EXE)
|
||||
|
||||
coverage: coverage_lib $(COVERAGE_EXE)
|
||||
|
||||
unitclean:
|
||||
rm -f *~
|
||||
rm -fr $(BUILD_DIR) $(COMMON_BUILD_DIR)
|
||||
|
||||
clean: unitclean
|
||||
|
||||
cleaner: unitclean
|
||||
@make -C $(LIB_DIR) clean
|
||||
|
||||
test_banner:
|
||||
@echo "===========" $(EXE) "=========== "
|
||||
|
||||
test: test_banner debug
|
||||
@$(DEBUG_EXE)
|
||||
|
||||
valgrind: test_banner debug
|
||||
@G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
|
||||
|
||||
$(DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(COVERAGE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(COMMON_DEBUG_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(COMMON_RELEASE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(COMMON_COVERAGE_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
|
||||
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(COMMON_DEBUG_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
|
||||
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(COMMON_RELEASE_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
|
||||
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(COMMON_COVERAGE_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
|
||||
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
|
||||
|
||||
$(DEBUG_EXE): $(DEBUG_LIB) $(DEBUG_OBJS)
|
||||
$(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
|
||||
|
||||
$(RELEASE_EXE): $(RELEASE_LIB) $(RELEASE_OBJS)
|
||||
$(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
|
||||
|
||||
$(COVERAGE_EXE): $(COVERAG_LIB) $(COVERAGE_OBJS)
|
||||
$(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
|
||||
|
||||
debug_lib:
|
||||
$(MAKE) -C $(LIB_DIR) $@
|
||||
|
||||
release_lib:
|
||||
$(MAKE) -C $(LIB_DIR) $@
|
||||
|
||||
coverage_lib:
|
||||
$(MAKE) -C $(LIB_DIR) $@
|
||||
108
unit/common/test_common.h
Normal file
108
unit/common/test_common.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TEST_COMMON_H
|
||||
#define TEST_COMMON_H
|
||||
|
||||
#include <radio_types.h>
|
||||
|
||||
#define TEST_FLAG_DEBUG (0x01)
|
||||
typedef struct test_opt {
|
||||
int flags;
|
||||
} TestOpt;
|
||||
|
||||
/* Should be invoked after g_test_init */
|
||||
void
|
||||
test_init(
|
||||
TestOpt* opt,
|
||||
int argc,
|
||||
char* argv[]);
|
||||
|
||||
/* Run loop with a timeout */
|
||||
void
|
||||
test_run(
|
||||
const TestOpt* opt,
|
||||
GMainLoop* loop);
|
||||
|
||||
/* Quits the event loop on the next iteration */
|
||||
void
|
||||
test_quit_later(
|
||||
GMainLoop* loop);
|
||||
|
||||
/* Quits the event loop after n iterations */
|
||||
void
|
||||
test_quit_later_n(
|
||||
GMainLoop* loop,
|
||||
guint n);
|
||||
|
||||
#define TEST_TIMEOUT_SEC (20)
|
||||
|
||||
/* Helper macros */
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
# define TEST_INT16_BYTES(v) \
|
||||
(guint8)(v), (guint8)((v) >> 8)
|
||||
# define TEST_INT32_BYTES(v) \
|
||||
(guint8)(v), (guint8)((v) >> 8), \
|
||||
(guint8)((v) >> 16), (guint8)((v) >> 24)
|
||||
# define TEST_INT64_BYTES(v) \
|
||||
(guint8)(v), (guint8)((v) >> 8), \
|
||||
(guint8)((v) >> 16), (guint8)((v) >> 24), \
|
||||
(guint8)(((guint64)(v)) >> 32), (guint8)(((guint64)(v)) >> 40), \
|
||||
(guint8)(((guint64)(v)) >> 48), (guint8)(((guint64)(v)) >> 56)
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
# define TEST_INT16_BYTES(v) \
|
||||
(guint8)((v) >> 8), (guint8)(v)
|
||||
# define TEST_INT32_BYTES(v) \
|
||||
(guint8)((v) >> 24), (guint8)((v) >> 16), \
|
||||
(guint8)((v) >> 8), (guint8)(v)
|
||||
# define TEST_INT64_BYTES(v) \
|
||||
(guint8)(((guint64)(v)) >> 56), (guint8)(((guint64)(v)) >> 48), \
|
||||
(guint8)(((guint64)(v)) >> 40), (guint8)(((guint64)(v)) >> 32), \
|
||||
(guint8)((v) >> 24), (guint8)((v) >> 16), \
|
||||
(guint8)((v) >> 8), (guint8)(v)
|
||||
#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
|
||||
#error unknown ENDIAN type
|
||||
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
|
||||
|
||||
#define TEST_ARRAY_AND_COUNT(a) a, G_N_ELEMENTS(a)
|
||||
#define TEST_ARRAY_AND_SIZE(a) a, sizeof(a)
|
||||
|
||||
#endif /* TEST_COMMON_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
161
unit/common/test_gbinder.h
Normal file
161
unit/common/test_gbinder.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TEST_GBINDER_H
|
||||
#define TEST_GBINDER_H
|
||||
|
||||
#include <gbinder.h>
|
||||
|
||||
typedef struct test_gbinder_data TestGBinderData;
|
||||
|
||||
/* test_gbinder_reader_writer.c */
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_data_new(
|
||||
void);
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_data_ref(
|
||||
TestGBinderData* data);
|
||||
|
||||
void
|
||||
test_gbinder_data_unref(
|
||||
TestGBinderData* data);
|
||||
|
||||
void
|
||||
test_gbinder_data_add_int32(
|
||||
TestGBinderData* data,
|
||||
guint32 value);
|
||||
|
||||
void
|
||||
test_gbinder_data_add_hidl_struct(
|
||||
TestGBinderData* data,
|
||||
const void* buf,
|
||||
gsize size);
|
||||
|
||||
void
|
||||
test_gbinder_data_init_reader(
|
||||
TestGBinderData* data,
|
||||
GBinderReader* reader);
|
||||
|
||||
void
|
||||
test_gbinder_data_init_writer(
|
||||
TestGBinderData* data,
|
||||
GBinderWriter* writer);
|
||||
|
||||
/* test_gbinder_local_request.c */
|
||||
|
||||
GBinderLocalRequest*
|
||||
test_gbinder_local_request_new(
|
||||
const char* iface);
|
||||
|
||||
const char*
|
||||
test_gbinder_local_request_interface(
|
||||
GBinderLocalRequest* local);
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_local_request_data(
|
||||
GBinderLocalRequest* local);
|
||||
|
||||
/* test_gbinder_local_reply.c */
|
||||
|
||||
GBinderLocalReply*
|
||||
test_gbinder_local_reply_new(
|
||||
void);
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_local_reply_data(
|
||||
GBinderLocalReply* reply);
|
||||
|
||||
/* test_gbinder_remote_request.c */
|
||||
|
||||
GBinderRemoteRequest*
|
||||
test_gbinder_remote_request_new(
|
||||
GBinderLocalRequest* req);
|
||||
|
||||
/* test_gbinder_remote_reply.c */
|
||||
|
||||
GBinderRemoteReply*
|
||||
test_gbinder_remote_reply_new(
|
||||
GBinderLocalReply* reply);
|
||||
|
||||
/* test_gbinder_local_object.c */
|
||||
|
||||
GBinderLocalObject*
|
||||
test_gbinder_local_object_new(
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data);
|
||||
|
||||
GBinderLocalReply*
|
||||
test_gbinder_local_object_handle_tx(
|
||||
GBinderLocalObject* self,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status);
|
||||
|
||||
/* test_gbinder_remote_object.c */
|
||||
|
||||
GBinderRemoteObject*
|
||||
test_gbinder_remote_object_new(
|
||||
GBinderLocalObject* local);
|
||||
|
||||
void
|
||||
test_gbinder_remote_object_kill(
|
||||
GBinderRemoteObject* remote);
|
||||
|
||||
gboolean
|
||||
test_gbinder_remote_object_dead(
|
||||
GBinderRemoteObject* remote);
|
||||
|
||||
GBinderLocalObject*
|
||||
test_gbinder_remote_object_to_local(
|
||||
GBinderRemoteObject* remote);
|
||||
|
||||
/* test_gbinder_servicemanager.c */
|
||||
|
||||
GBinderRemoteObject*
|
||||
test_gbinder_servicemanager_new_service(
|
||||
GBinderServiceManager* manager,
|
||||
const char* name,
|
||||
GBinderLocalObject* local);
|
||||
|
||||
#endif /* TEST_GBINDER_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
366
unit/common/test_gbinder_client.c
Normal file
366
unit/common/test_gbinder_client.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
typedef struct test_gbinder_client_tx {
|
||||
GBinderClient* client;
|
||||
guint32 code;
|
||||
guint32 flags;
|
||||
GBinderLocalRequest* req;
|
||||
GBinderClientReplyFunc reply;
|
||||
GDestroyNotify destroy;
|
||||
void* user_data;
|
||||
} TestGBinderClientTx;
|
||||
|
||||
typedef struct test_gbinder_client_iface_range {
|
||||
char* iface;
|
||||
guint32 last_code;
|
||||
} TestGBinderClientIfaceRange;
|
||||
|
||||
struct gbinder_client {
|
||||
guint32 refcount;
|
||||
GBinderRemoteObject* remote;
|
||||
TestGBinderClientIfaceRange* ranges;
|
||||
guint nr;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_client_free(
|
||||
GBinderClient* self)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->nr; i++) {
|
||||
g_free(self->ranges[i].iface);
|
||||
}
|
||||
g_free(self->ranges);
|
||||
gbinder_remote_object_unref(self->remote);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_client_init_range(
|
||||
TestGBinderClientIfaceRange* r,
|
||||
const GBinderClientIfaceInfo* info)
|
||||
{
|
||||
r->iface = g_strdup(info->iface);
|
||||
r->last_code = info->last_code;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
test_gbinder_client_sort_ranges(
|
||||
const void* p1,
|
||||
const void* p2)
|
||||
{
|
||||
const TestGBinderClientIfaceRange* r1 = p1;
|
||||
const TestGBinderClientIfaceRange* r2 = p2;
|
||||
|
||||
return (r1->last_code < r2->last_code) ? (-1) :
|
||||
(r1->last_code > r2->last_code) ? 1 : 0;
|
||||
}
|
||||
|
||||
static
|
||||
const TestGBinderClientIfaceRange*
|
||||
test_gbinder_client_find_range(
|
||||
GBinderClient* self,
|
||||
guint32 code)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->nr; i++) {
|
||||
const TestGBinderClientIfaceRange* r = self->ranges + i;
|
||||
|
||||
if (r->last_code >= code) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderRemoteReply*
|
||||
test_gbinder_client_transact(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
guint32 flags,
|
||||
GBinderLocalRequest* req,
|
||||
int* status)
|
||||
{
|
||||
GBinderLocalObject* obj = test_gbinder_remote_object_to_local(self->remote);
|
||||
GBinderRemoteRequest* remote_req = test_gbinder_remote_request_new(req);
|
||||
GBinderLocalReply* reply = test_gbinder_local_object_handle_tx(obj,
|
||||
remote_req, code, flags, status);
|
||||
GBinderRemoteReply* remote_reply = test_gbinder_remote_reply_new(reply);
|
||||
|
||||
gbinder_remote_request_unref(remote_req);
|
||||
gbinder_local_reply_unref(reply);
|
||||
return remote_reply;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderRemoteReply*
|
||||
test_gbinder_client_transact_sync(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
guint32 flags,
|
||||
GBinderLocalRequest* req,
|
||||
int* status)
|
||||
{
|
||||
GBinderRemoteReply* reply = NULL;
|
||||
|
||||
if (self) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
if (!test_gbinder_remote_object_dead(obj)) {
|
||||
GBinderLocalRequest* tmp = NULL;
|
||||
|
||||
if (!req) {
|
||||
const TestGBinderClientIfaceRange* r =
|
||||
test_gbinder_client_find_range(self, code);
|
||||
|
||||
if (r) {
|
||||
req = tmp = test_gbinder_local_request_new(r->iface);
|
||||
}
|
||||
}
|
||||
if (req) {
|
||||
reply = test_gbinder_client_transact(self, code, flags, req,
|
||||
status);
|
||||
}
|
||||
gbinder_local_request_unref(tmp);
|
||||
} else {
|
||||
GDEBUG("Refusing to perform transaction with a dead object");
|
||||
}
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_gbinder_client_tx_handle(
|
||||
gpointer data)
|
||||
{
|
||||
int status = -1;
|
||||
TestGBinderClientTx* tx = data;
|
||||
GBinderRemoteReply* reply = test_gbinder_client_transact
|
||||
(tx->client, tx->code, tx->flags, tx->req, &status);
|
||||
|
||||
tx->reply(tx->client, reply, status, tx->user_data);
|
||||
gbinder_remote_reply_unref(reply);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_client_tx_destroy(
|
||||
gpointer data)
|
||||
{
|
||||
TestGBinderClientTx* tx = data;
|
||||
|
||||
if (tx->destroy) {
|
||||
tx->destroy(tx->user_data);
|
||||
}
|
||||
gbinder_local_request_unref(tx->req);
|
||||
gbinder_client_unref(tx->client);
|
||||
g_free(tx);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderClient*
|
||||
gbinder_client_new2(
|
||||
GBinderRemoteObject* remote,
|
||||
const GBinderClientIfaceInfo* ifaces,
|
||||
gsize count)
|
||||
{
|
||||
if (remote) {
|
||||
GBinderClient* self = g_new0(GBinderClient, 1);
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->remote = gbinder_remote_object_ref(remote);
|
||||
if (count > 0) {
|
||||
gsize i;
|
||||
|
||||
self->nr = count;
|
||||
self->ranges = g_new(TestGBinderClientIfaceRange, self->nr);
|
||||
for (i = 0; i < count; i++) {
|
||||
test_gbinder_client_init_range(self->ranges + i, ifaces + i);
|
||||
}
|
||||
qsort(self->ranges, count, sizeof(TestGBinderClientIfaceRange),
|
||||
test_gbinder_client_sort_ranges);
|
||||
} else {
|
||||
/* No interface info */
|
||||
self->nr = 1;
|
||||
self->ranges = g_new0(TestGBinderClientIfaceRange, 1);
|
||||
self->ranges[0].last_code = UINT_MAX;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderClient*
|
||||
gbinder_client_ref(
|
||||
GBinderClient* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_client_unref(
|
||||
GBinderClient* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_client_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_client_new_request2(
|
||||
GBinderClient* self,
|
||||
guint32 code)
|
||||
{
|
||||
if (self) {
|
||||
const TestGBinderClientIfaceRange* r =
|
||||
test_gbinder_client_find_range(self, code);
|
||||
|
||||
if (r) {
|
||||
return test_gbinder_local_request_new(r->iface);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderRemoteReply*
|
||||
gbinder_client_transact_sync_reply(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req,
|
||||
int* status)
|
||||
{
|
||||
return test_gbinder_client_transact_sync(self, code, 0, req, status);
|
||||
}
|
||||
|
||||
int
|
||||
gbinder_client_transact_sync_oneway(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
GBinderLocalRequest* req)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
g_assert(!test_gbinder_client_transact_sync(self, code,
|
||||
GBINDER_TX_FLAG_ONEWAY, req, &status));
|
||||
return status;
|
||||
}
|
||||
|
||||
gulong
|
||||
gbinder_client_transact(
|
||||
GBinderClient* self,
|
||||
guint32 code,
|
||||
guint32 flags,
|
||||
GBinderLocalRequest* req,
|
||||
GBinderClientReplyFunc reply,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
gulong id = 0;
|
||||
|
||||
if (self) {
|
||||
GBinderRemoteObject* obj = self->remote;
|
||||
|
||||
if (!test_gbinder_remote_object_dead(obj)) {
|
||||
GBinderLocalRequest* tmp = NULL;
|
||||
|
||||
if (!req) {
|
||||
const TestGBinderClientIfaceRange* r =
|
||||
test_gbinder_client_find_range(self, code);
|
||||
|
||||
if (r) {
|
||||
req = tmp = test_gbinder_local_request_new(r->iface);
|
||||
}
|
||||
}
|
||||
if (req) {
|
||||
TestGBinderClientTx* tx = g_new0(TestGBinderClientTx, 1);
|
||||
|
||||
tx->client = gbinder_client_ref(self);
|
||||
tx->code = code;
|
||||
tx->flags = flags;
|
||||
tx->req = gbinder_local_request_ref(req);
|
||||
tx->reply = reply;
|
||||
tx->destroy = destroy;
|
||||
tx->user_data = user_data;
|
||||
id = g_idle_add_full(G_PRIORITY_DEFAULT,
|
||||
test_gbinder_client_tx_handle, tx,
|
||||
test_gbinder_client_tx_destroy);
|
||||
}
|
||||
gbinder_local_request_unref(tmp);
|
||||
} else {
|
||||
GDEBUG("Refusing to perform transaction with a dead object");
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_client_cancel(
|
||||
GBinderClient* self,
|
||||
gulong id)
|
||||
{
|
||||
g_source_remove((guint)id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
153
unit/common/test_gbinder_local_object.c
Normal file
153
unit/common/test_gbinder_local_object.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
|
||||
struct gbinder_local_object {
|
||||
guint32 refcount;
|
||||
char** ifaces;
|
||||
GBinderLocalTransactFunc txproc;
|
||||
void* user_data;
|
||||
};
|
||||
|
||||
static const char hidl_base_interface[] = "android.hidl.base@1.0::IBase";
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_local_object_free(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
g_strfreev(self->ifaces);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderLocalObject*
|
||||
test_gbinder_local_object_new(
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc txproc,
|
||||
void* user_data)
|
||||
{
|
||||
GBinderLocalObject* self = g_new0(GBinderLocalObject, 1);
|
||||
guint i = 0, n = gutil_strv_length((char**)ifaces);
|
||||
gboolean append_base_interface;
|
||||
|
||||
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
|
||||
append_base_interface = TRUE;
|
||||
n++;
|
||||
} else {
|
||||
append_base_interface = FALSE;
|
||||
}
|
||||
|
||||
self->ifaces = g_new(char*, n + 1);
|
||||
if (ifaces) {
|
||||
while (*ifaces) {
|
||||
self->ifaces[i++] = g_strdup(*ifaces++);
|
||||
}
|
||||
}
|
||||
if (append_base_interface) {
|
||||
self->ifaces[i++] = g_strdup(hidl_base_interface);
|
||||
}
|
||||
self->ifaces[i] = NULL;
|
||||
self->txproc = txproc;
|
||||
self->user_data = user_data;
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
return self;
|
||||
}
|
||||
|
||||
GBinderLocalReply*
|
||||
test_gbinder_local_object_handle_tx(
|
||||
GBinderLocalObject* self,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status)
|
||||
{
|
||||
return (self && self->txproc) ?
|
||||
self->txproc(self, req, code, flags, status, self->user_data) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_local_object_ref(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_object_unref(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_local_object_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_object_drop(
|
||||
GBinderLocalObject* self)
|
||||
{
|
||||
if (self) {
|
||||
self->txproc = NULL;
|
||||
self->user_data = NULL;
|
||||
gbinder_local_object_unref(self);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
118
unit/common/test_gbinder_local_reply.c
Normal file
118
unit/common/test_gbinder_local_reply.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
struct gbinder_local_reply {
|
||||
guint32 refcount;
|
||||
TestGBinderData* data;
|
||||
char* iface;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_local_reply_free(
|
||||
GBinderLocalReply* self)
|
||||
{
|
||||
test_gbinder_data_unref(self->data);
|
||||
g_free(self->iface);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderLocalReply*
|
||||
test_gbinder_local_reply_new(
|
||||
void)
|
||||
{
|
||||
GBinderLocalReply* self = g_new0(GBinderLocalReply, 1);
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->data = test_gbinder_data_new();
|
||||
return self;
|
||||
}
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_local_reply_data(
|
||||
GBinderLocalReply* self)
|
||||
{
|
||||
return self ? self->data : NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderLocalReply*
|
||||
gbinder_local_reply_ref(
|
||||
GBinderLocalReply* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_reply_unref(
|
||||
GBinderLocalReply* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_local_reply_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_reply_init_writer(
|
||||
GBinderLocalReply* self,
|
||||
GBinderWriter* writer)
|
||||
{
|
||||
test_gbinder_data_init_writer(self->data, writer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
141
unit/common/test_gbinder_local_request.c
Normal file
141
unit/common/test_gbinder_local_request.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
struct gbinder_local_request {
|
||||
guint32 refcount;
|
||||
TestGBinderData* data;
|
||||
char* iface;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_local_request_free(
|
||||
GBinderLocalRequest* self)
|
||||
{
|
||||
test_gbinder_data_unref(self->data);
|
||||
g_free(self->iface);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderLocalRequest*
|
||||
test_gbinder_local_request_new(
|
||||
const char* iface)
|
||||
{
|
||||
GBinderLocalRequest* self = g_new0(GBinderLocalRequest, 1);
|
||||
|
||||
g_assert(iface);
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->data = test_gbinder_data_new();
|
||||
self->iface = g_strdup(iface);
|
||||
return self;
|
||||
}
|
||||
|
||||
const char*
|
||||
test_gbinder_local_request_interface(
|
||||
GBinderLocalRequest* self)
|
||||
{
|
||||
return self ? self->iface : NULL;
|
||||
}
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_local_request_data(
|
||||
GBinderLocalRequest* self)
|
||||
{
|
||||
return self ? self->data : NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_ref(
|
||||
GBinderLocalRequest* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_request_unref(
|
||||
GBinderLocalRequest* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_local_request_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_local_request_init_writer(
|
||||
GBinderLocalRequest* self,
|
||||
GBinderWriter* writer)
|
||||
{
|
||||
test_gbinder_data_init_writer(self->data, writer);
|
||||
}
|
||||
|
||||
GBinderLocalRequest*
|
||||
gbinder_local_request_append_int32(
|
||||
GBinderLocalRequest* self,
|
||||
guint32 value)
|
||||
{
|
||||
if (self) {
|
||||
GBinderWriter writer;
|
||||
|
||||
test_gbinder_data_init_writer(self->data, &writer);
|
||||
gbinder_writer_append_int32(&writer, value);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
324
unit/common/test_gbinder_reader_writer.c
Normal file
324
unit/common/test_gbinder_reader_writer.c
Normal file
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
#include <gutil_macros.h>
|
||||
|
||||
typedef enum test_gbinder_data_type {
|
||||
DATA_TYPE_INT32,
|
||||
DATA_TYPE_BUFFER,
|
||||
DATA_TYPE_LOCAL_OBJ
|
||||
} DATA_TYPE;
|
||||
|
||||
typedef struct test_gbinder_data_item TestGBinderDataItem;
|
||||
struct test_gbinder_data_item {
|
||||
TestGBinderDataItem* next;
|
||||
DATA_TYPE type;
|
||||
union {
|
||||
gint32 i32;
|
||||
struct {
|
||||
const void* buf;
|
||||
gsize size;
|
||||
} blob;
|
||||
GBinderLocalObject* obj;
|
||||
} data;
|
||||
void (*destroy)(TestGBinderDataItem*);
|
||||
};
|
||||
|
||||
struct test_gbinder_data {
|
||||
guint32 refcount;
|
||||
TestGBinderDataItem* items;
|
||||
};
|
||||
|
||||
typedef struct test_gbinder_reader {
|
||||
TestGBinderDataItem* item;
|
||||
} TestGBinderReader;
|
||||
|
||||
typedef struct test_gbinder_writer {
|
||||
TestGBinderData* data;
|
||||
} TestGBinderWriter;
|
||||
|
||||
static inline TestGBinderReader* test_gbinder_reader_cast(GBinderReader* reader)
|
||||
{ return (TestGBinderReader*)reader; }
|
||||
|
||||
static inline TestGBinderWriter* test_gbinder_writer_cast(GBinderWriter* writer)
|
||||
{ return (TestGBinderWriter*)writer; }
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_data_item_destroy_local_obj(
|
||||
TestGBinderDataItem* item)
|
||||
{
|
||||
g_assert_cmpint(item->type, == ,DATA_TYPE_LOCAL_OBJ);
|
||||
gbinder_local_object_unref(item->data.obj);
|
||||
}
|
||||
|
||||
static
|
||||
TestGBinderDataItem*
|
||||
test_gbinder_data_item_new(
|
||||
DATA_TYPE type)
|
||||
{
|
||||
TestGBinderDataItem* item = g_new0(TestGBinderDataItem, 1);
|
||||
|
||||
item->type = type;
|
||||
return item;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_data_item_free(
|
||||
TestGBinderDataItem* item)
|
||||
{
|
||||
if (item) {
|
||||
test_gbinder_data_item_free(item->next);
|
||||
if (item->destroy) {
|
||||
item->destroy(item);
|
||||
}
|
||||
g_free(item);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_data_free(
|
||||
TestGBinderData* data)
|
||||
{
|
||||
test_gbinder_data_item_free(data->items);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
test_gbinder_data_count_buffers(
|
||||
TestGBinderData* data)
|
||||
{
|
||||
TestGBinderDataItem* item;
|
||||
guint n;
|
||||
|
||||
for (n = 0, item = data->items; item; item = item->next) {
|
||||
if (item->type == DATA_TYPE_BUFFER) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_data_append(
|
||||
TestGBinderData* data,
|
||||
TestGBinderDataItem* item)
|
||||
{
|
||||
TestGBinderDataItem* last = data->items;
|
||||
|
||||
if (last) {
|
||||
while (last->next) {
|
||||
last = last->next;
|
||||
}
|
||||
last->next = item;
|
||||
} else {
|
||||
data->items = item;
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_data_new(
|
||||
void)
|
||||
{
|
||||
TestGBinderData* data = g_new0(TestGBinderData, 1);
|
||||
|
||||
g_atomic_int_set(&data->refcount, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
TestGBinderData*
|
||||
test_gbinder_data_ref(
|
||||
TestGBinderData* data)
|
||||
{
|
||||
if (data) {
|
||||
g_assert_cmpint(data->refcount, > ,0);
|
||||
g_atomic_int_inc(&data->refcount);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
test_gbinder_data_unref(
|
||||
TestGBinderData* data)
|
||||
{
|
||||
if (data) {
|
||||
g_assert_cmpint(data->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&data->refcount)) {
|
||||
test_gbinder_data_free(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_gbinder_data_init_reader(
|
||||
TestGBinderData* data,
|
||||
GBinderReader* reader)
|
||||
{
|
||||
memset(reader, 0, sizeof(*reader));
|
||||
if (data) {
|
||||
test_gbinder_reader_cast(reader)->item = data->items;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_gbinder_data_init_writer(
|
||||
TestGBinderData* data,
|
||||
GBinderWriter* writer)
|
||||
{
|
||||
memset(writer, 0, sizeof(*writer));
|
||||
if (data) {
|
||||
test_gbinder_writer_cast(writer)->data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_uint32(
|
||||
GBinderReader* reader,
|
||||
guint32* value)
|
||||
{
|
||||
TestGBinderReader* self = test_gbinder_reader_cast(reader);
|
||||
TestGBinderDataItem* item = self->item;
|
||||
|
||||
if (item && item->type == DATA_TYPE_INT32) {
|
||||
if (value) {
|
||||
*value = item->data.i32;
|
||||
}
|
||||
self->item = item->next;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gbinder_reader_read_int32(
|
||||
GBinderReader* reader,
|
||||
gint32* value)
|
||||
{
|
||||
return gbinder_reader_read_uint32(reader, (guint32*)value);
|
||||
}
|
||||
|
||||
const void*
|
||||
gbinder_reader_read_hidl_struct1(
|
||||
GBinderReader* reader,
|
||||
gsize size)
|
||||
{
|
||||
TestGBinderReader* self = test_gbinder_reader_cast(reader);
|
||||
TestGBinderDataItem* item = self->item;
|
||||
|
||||
if (item && item->type == DATA_TYPE_BUFFER &&
|
||||
item->data.blob.size == size) {
|
||||
self->item = item->next;
|
||||
return item->data.blob.buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_reader_read_object(
|
||||
GBinderReader* reader)
|
||||
{
|
||||
TestGBinderReader* self = test_gbinder_reader_cast(reader);
|
||||
TestGBinderDataItem* item = self->item;
|
||||
|
||||
if (item && item->type == DATA_TYPE_LOCAL_OBJ) {
|
||||
self->item = item->next;
|
||||
return test_gbinder_remote_object_new(item->data.obj);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_int32(
|
||||
GBinderWriter* writer,
|
||||
guint32 value)
|
||||
{
|
||||
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
|
||||
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_INT32);
|
||||
|
||||
item->data.i32 = value;
|
||||
test_gbinder_data_append(self->data, item);
|
||||
}
|
||||
|
||||
guint
|
||||
gbinder_writer_append_buffer_object(
|
||||
GBinderWriter* writer,
|
||||
const void* buf,
|
||||
gsize size)
|
||||
{
|
||||
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
|
||||
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_BUFFER);
|
||||
const guint index = test_gbinder_data_count_buffers(self->data);
|
||||
|
||||
item->data.blob.buf = buf;
|
||||
item->data.blob.size = size;
|
||||
test_gbinder_data_append(self->data, item);
|
||||
return index;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_writer_append_local_object(
|
||||
GBinderWriter* writer,
|
||||
GBinderLocalObject* obj)
|
||||
{
|
||||
TestGBinderWriter* self = test_gbinder_writer_cast(writer);
|
||||
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_LOCAL_OBJ);
|
||||
|
||||
item->data.obj = gbinder_local_object_ref(obj);
|
||||
item->destroy = test_gbinder_data_item_destroy_local_obj;
|
||||
test_gbinder_data_append(self->data, item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
180
unit/common/test_gbinder_remote_object.c
Normal file
180
unit/common/test_gbinder_remote_object.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
struct gbinder_remote_object {
|
||||
GObject parent;
|
||||
GBinderLocalObject* local;
|
||||
gboolean dead;
|
||||
};
|
||||
|
||||
typedef GObjectClass GBinderRemoteObjectClass;
|
||||
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
|
||||
|
||||
#define PARENT_CLASS gbinder_remote_object_parent_class
|
||||
#define THIS_TYPE (gbinder_remote_object_get_type())
|
||||
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,GBinderRemoteObject)
|
||||
|
||||
enum gbinder_remote_object_signal {
|
||||
SIGNAL_DEATH,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_DEATH_NAME "death"
|
||||
|
||||
static guint remote_object_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_remote_object_init(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_remote_object_finalize(
|
||||
GObject* object)
|
||||
{
|
||||
GBinderRemoteObject* self = THIS(object);
|
||||
|
||||
gbinder_local_object_unref(self->local);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
gbinder_remote_object_class_init(
|
||||
GBinderRemoteObjectClass* klass)
|
||||
{
|
||||
G_OBJECT_CLASS(klass)->finalize = gbinder_remote_object_finalize;
|
||||
remote_object_signals[SIGNAL_DEATH] =
|
||||
g_signal_new(SIGNAL_DEATH_NAME, G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteObject*
|
||||
test_gbinder_remote_object_new(
|
||||
GBinderLocalObject* local)
|
||||
{
|
||||
GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
|
||||
|
||||
g_assert(local);
|
||||
self->local = gbinder_local_object_ref(local);
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
test_gbinder_remote_object_kill(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
if (self && !self->dead) {
|
||||
self->dead = TRUE;
|
||||
g_signal_emit(self, remote_object_signals[SIGNAL_DEATH], 0);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
test_gbinder_remote_object_dead(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
return !self || self->dead;
|
||||
}
|
||||
|
||||
GBinderLocalObject*
|
||||
test_gbinder_remote_object_to_local(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
return self ? self->local : NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteObject*
|
||||
gbinder_remote_object_ref(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_ref(THIS(self));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_object_unref(
|
||||
GBinderRemoteObject* self)
|
||||
{
|
||||
if (self) {
|
||||
g_object_unref(THIS(self));
|
||||
}
|
||||
}
|
||||
|
||||
gulong
|
||||
gbinder_remote_object_add_death_handler(
|
||||
GBinderRemoteObject* self,
|
||||
GBinderRemoteObjectNotifyFunc fn,
|
||||
void* data)
|
||||
{
|
||||
return (self && fn) ? g_signal_connect(self, SIGNAL_DEATH_NAME,
|
||||
G_CALLBACK(fn), data) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_object_remove_handler(
|
||||
GBinderRemoteObject* self,
|
||||
gulong id)
|
||||
{
|
||||
if (self && id) {
|
||||
g_signal_handler_disconnect(self, id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remote Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
106
unit/common/test_gbinder_remote_reply.c
Normal file
106
unit/common/test_gbinder_remote_reply.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
struct gbinder_remote_reply {
|
||||
guint32 refcount;
|
||||
TestGBinderData* data;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_remote_reply_free(
|
||||
GBinderRemoteReply* self)
|
||||
{
|
||||
test_gbinder_data_unref(self->data);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteReply*
|
||||
test_gbinder_remote_reply_new(
|
||||
GBinderLocalReply* reply)
|
||||
{
|
||||
if (reply) {
|
||||
GBinderRemoteReply* self = g_new0(GBinderRemoteReply, 1);
|
||||
TestGBinderData* data = test_gbinder_local_reply_data(reply);
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->data = test_gbinder_data_ref(data);
|
||||
return self;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteReply*
|
||||
gbinder_remote_reply_ref(
|
||||
GBinderRemoteReply* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_reply_unref(
|
||||
GBinderRemoteReply* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_remote_reply_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
119
unit/common/test_gbinder_remote_request.c
Normal file
119
unit/common/test_gbinder_remote_request.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
struct gbinder_remote_request {
|
||||
guint32 refcount;
|
||||
TestGBinderData* data;
|
||||
char* iface;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_remote_request_free(
|
||||
GBinderRemoteRequest* self)
|
||||
{
|
||||
test_gbinder_data_unref(self->data);
|
||||
g_free(self->iface);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteRequest*
|
||||
test_gbinder_remote_request_new(
|
||||
GBinderLocalRequest* req)
|
||||
{
|
||||
GBinderRemoteRequest* self = g_new0(GBinderRemoteRequest, 1);
|
||||
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->data = test_gbinder_data_ref(test_gbinder_local_request_data(req));
|
||||
self->iface = g_strdup(test_gbinder_local_request_interface(req));
|
||||
return self;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteRequest*
|
||||
gbinder_remote_request_ref(
|
||||
GBinderRemoteRequest* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_request_unref(
|
||||
GBinderRemoteRequest* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_remote_request_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
gbinder_remote_request_interface(
|
||||
GBinderRemoteRequest* self)
|
||||
{
|
||||
return self ? self->iface : NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_remote_request_init_reader(
|
||||
GBinderRemoteRequest* self,
|
||||
GBinderReader* reader)
|
||||
{
|
||||
test_gbinder_data_init_reader(self->data, reader);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
180
unit/common/test_gbinder_servicemanager.c
Normal file
180
unit/common/test_gbinder_servicemanager.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_gbinder.h"
|
||||
|
||||
#include <gutil_idlepool.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
struct gbinder_servicemanager {
|
||||
guint32 refcount;
|
||||
GHashTable* services;
|
||||
GUtilIdlePool* pool;
|
||||
char* dev;
|
||||
};
|
||||
|
||||
static GHashTable* test_servermanagers = NULL;
|
||||
|
||||
static
|
||||
void
|
||||
test_gbinder_servicemanager_free(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
/* Update the global table */
|
||||
g_assert(test_servermanagers);
|
||||
g_assert(g_hash_table_contains(test_servermanagers, self->dev));
|
||||
g_hash_table_remove(test_servermanagers, self->dev); /* Frees self->dev */
|
||||
if (g_hash_table_size(test_servermanagers) == 0) {
|
||||
g_hash_table_unref(test_servermanagers);
|
||||
test_servermanagers = NULL;
|
||||
}
|
||||
|
||||
gutil_idle_pool_destroy(self->pool);
|
||||
g_hash_table_destroy(self->services);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internal API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderRemoteObject*
|
||||
test_gbinder_servicemanager_new_service(
|
||||
GBinderServiceManager* self,
|
||||
const char* name,
|
||||
GBinderLocalObject* local)
|
||||
{
|
||||
GBinderRemoteObject* remote = test_gbinder_remote_object_new(local);
|
||||
|
||||
g_hash_table_replace(self->services, g_strdup(name), remote);
|
||||
return gbinder_remote_object_ref(remote);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* libgbinder API
|
||||
*==========================================================================*/
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicemanager_new(
|
||||
const char* dev)
|
||||
{
|
||||
GBinderServiceManager* self = NULL;
|
||||
|
||||
g_assert(dev && dev[0]);
|
||||
if (test_servermanagers) {
|
||||
self = g_hash_table_lookup(test_servermanagers, dev);
|
||||
}
|
||||
|
||||
if (self) {
|
||||
gbinder_servicemanager_ref(self);
|
||||
} else {
|
||||
self = g_new0(GBinderServiceManager, 1);
|
||||
g_atomic_int_set(&self->refcount, 1);
|
||||
self->pool = gutil_idle_pool_new();
|
||||
self->dev = g_strdup(dev); /* Owned by test_servermanagers */
|
||||
self->services = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
||||
(GDestroyNotify) gbinder_remote_object_unref);
|
||||
|
||||
/* Update the global table */
|
||||
if (!test_servermanagers) {
|
||||
test_servermanagers = g_hash_table_new_full(g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
}
|
||||
g_hash_table_replace(test_servermanagers, self->dev, self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
GBinderServiceManager*
|
||||
gbinder_servicemanager_ref(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
g_atomic_int_inc(&self->refcount);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gbinder_servicemanager_unref(
|
||||
GBinderServiceManager* self)
|
||||
{
|
||||
if (self) {
|
||||
g_assert_cmpint(self->refcount, > ,0);
|
||||
if (g_atomic_int_dec_and_test(&self->refcount)) {
|
||||
test_gbinder_servicemanager_free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GBinderRemoteObject* /* autoreleased */
|
||||
gbinder_servicemanager_get_service_sync(
|
||||
GBinderServiceManager* self,
|
||||
const char* name,
|
||||
int* status)
|
||||
{
|
||||
if (self && name) {
|
||||
GBinderRemoteObject* obj = g_hash_table_lookup(self->services, name);
|
||||
|
||||
if (obj) {
|
||||
gutil_idle_pool_add(self->pool, gbinder_remote_object_ref(obj),
|
||||
(GDestroyNotify) gbinder_remote_object_unref);
|
||||
return obj;
|
||||
} else {
|
||||
GDEBUG("Name %s not found", name);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GBinderLocalObject*
|
||||
gbinder_servicemanager_new_local_object2(
|
||||
GBinderServiceManager* self,
|
||||
const char* const* ifaces,
|
||||
GBinderLocalTransactFunc fn,
|
||||
void* user_data)
|
||||
{
|
||||
return self ? test_gbinder_local_object_new(ifaces, fn, user_data) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
166
unit/common/test_main.c
Normal file
166
unit/common/test_main.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 Jolla Ltd.
|
||||
* Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
#include <gutil_log.h>
|
||||
|
||||
typedef struct test_quit_later_data{
|
||||
GMainLoop* loop;
|
||||
guint n;
|
||||
} TestQuitLaterData;
|
||||
|
||||
typedef struct test_context_data{
|
||||
GMainLoop* loop;
|
||||
GTestFunc func;
|
||||
} TestContextData;
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_timeout_expired(
|
||||
gpointer data)
|
||||
{
|
||||
g_assert(!"TIMEOUT");
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_quit_later_n_free(
|
||||
gpointer user_data)
|
||||
{
|
||||
TestQuitLaterData* data = user_data;
|
||||
|
||||
g_main_loop_unref(data->loop);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_quit_later_n_func(
|
||||
gpointer user_data)
|
||||
{
|
||||
TestQuitLaterData* data = user_data;
|
||||
|
||||
if (data->n > 0) {
|
||||
data->n--;
|
||||
return G_SOURCE_CONTINUE;
|
||||
} else {
|
||||
g_main_loop_quit(data->loop);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_quit_later_n(
|
||||
GMainLoop* loop,
|
||||
guint n)
|
||||
{
|
||||
TestQuitLaterData* data = g_new0(TestQuitLaterData, 1);
|
||||
|
||||
data->loop = g_main_loop_ref(loop);
|
||||
data->n = n;
|
||||
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_quit_later_n_func, data,
|
||||
test_quit_later_n_free);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_quit_later_cb(
|
||||
gpointer data)
|
||||
{
|
||||
g_main_loop_quit((GMainLoop*)data);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
test_quit_later(
|
||||
GMainLoop* loop)
|
||||
{
|
||||
g_idle_add(test_quit_later_cb, loop);
|
||||
}
|
||||
|
||||
void
|
||||
test_run(
|
||||
const TestOpt* opt,
|
||||
GMainLoop* loop)
|
||||
{
|
||||
if (opt->flags & TEST_FLAG_DEBUG) {
|
||||
g_main_loop_run(loop);
|
||||
} else {
|
||||
const guint timeout_id = g_timeout_add_seconds(TEST_TIMEOUT_SEC,
|
||||
test_timeout_expired, NULL);
|
||||
g_main_loop_run(loop);
|
||||
g_source_remove(timeout_id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_init(
|
||||
TestOpt* opt,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
const char* sep1;
|
||||
const char* sep2;
|
||||
int i;
|
||||
|
||||
memset(opt, 0, sizeof(*opt));
|
||||
for (i=1; i<argc; i++) {
|
||||
const char* arg = argv[i];
|
||||
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
|
||||
opt->flags |= TEST_FLAG_DEBUG;
|
||||
} else if (!strcmp(arg, "-v")) {
|
||||
GTestConfig* config = (GTestConfig*)g_test_config_vars;
|
||||
config->test_verbose = TRUE;
|
||||
} else {
|
||||
GWARN("Unsupported command line option %s", arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup logging */
|
||||
sep1 = strrchr(argv[0], '/');
|
||||
sep2 = strrchr(argv[0], '\\');
|
||||
gutil_log_default.name = (sep1 && sep2) ? (MAX(sep1, sep2) + 1) :
|
||||
sep1 ? (sep1 + 1) : sep2 ? (sep2 + 1) : argv[0];
|
||||
gutil_log_default.level = g_test_verbose() ?
|
||||
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
|
||||
gutil_log_timestamp = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
54
unit/coverage/run
Executable file
54
unit/coverage/run
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script requires lcov, dirname
|
||||
#
|
||||
|
||||
TESTS="\
|
||||
unit_instance \
|
||||
unit_registry \
|
||||
unit_util"
|
||||
|
||||
function err() {
|
||||
echo "*** ERROR!" $1
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check the required tools
|
||||
which lcov >> /dev/null || err "Please install lcov"
|
||||
which dirname >> /dev/null || err "Please install dirname"
|
||||
|
||||
# LCOV 1.10 has branch coverage disabled per default
|
||||
# Previous versions didn't have the --rc option
|
||||
if [ ! -z "$(lcov --help | grep ' --rc ')" ] ; then
|
||||
LCOV_OPT="--rc lcov_branch_coverage=1"
|
||||
GENHTML_OPT="--branch-coverage"
|
||||
fi
|
||||
|
||||
pushd `dirname $0` > /dev/null
|
||||
COV_DIR="$PWD"
|
||||
pushd .. > /dev/null
|
||||
TEST_DIR="$PWD"
|
||||
pushd .. > /dev/null
|
||||
TOP_DIR="$PWD"
|
||||
popd > /dev/null
|
||||
popd > /dev/null
|
||||
popd > /dev/null
|
||||
|
||||
make -C "$TOP_DIR" clean
|
||||
for t in $TESTS ; do
|
||||
pushd "$TEST_DIR/$t"
|
||||
make -C "$TEST_DIR/$t" clean coverage || exit 1
|
||||
build/coverage/$t || exit 1
|
||||
popd
|
||||
done
|
||||
|
||||
# Sometimes you need this, sometimes that :S
|
||||
BASE_DIR="$TOP_DIR"
|
||||
#BASE_DIR="$TOP_DIR/src"
|
||||
|
||||
FULL_COV="$COV_DIR/full.gcov"
|
||||
LIB_COV="$COV_DIR/lib.gcov"
|
||||
rm -f "$FULL_COV" "$LIB_COV"
|
||||
lcov $LCOV_OPT -c -d "$TOP_DIR/build/coverage" -b "$BASE_DIR" -o "$FULL_COV" || exit 1
|
||||
lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/*" -o "$LIB_COV" || exit 1
|
||||
genhtml $GENHTML_OPT "$LIB_COV" -t "libgbinder-radio" --output-directory "$COV_DIR/report" || exit 1
|
||||
5
unit/unit_instance/Makefile
Normal file
5
unit/unit_instance/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
EXE = unit_instance
|
||||
|
||||
include ../common/Makefile
|
||||
820
unit/unit_instance/unit_instance.c
Normal file
820
unit/unit_instance/unit_instance.c
Normal file
@@ -0,0 +1,820 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_common.h"
|
||||
#include "test_gbinder.h"
|
||||
|
||||
#include "radio_instance.h"
|
||||
#include "radio_util.h"
|
||||
|
||||
#include <gutil_strv.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#define DEFAULT_INTERFACE RADIO_INTERFACE_1_0
|
||||
#define DEV GBINDER_DEFAULT_BINDER
|
||||
|
||||
#define UNKNOWN_VALUE (0x7fffffff)
|
||||
#define UNKNOWN_VALUE_STR "2147483647" /* 0x7fffffff */
|
||||
#define UNKNOWN_REQ ((RADIO_REQ)UNKNOWN_VALUE)
|
||||
#define UNKNOWN_REQ_STR UNKNOWN_VALUE_STR
|
||||
#define UNKNOWN_IND ((RADIO_IND)UNKNOWN_VALUE)
|
||||
#define UNKNOWN_IND_STR UNKNOWN_VALUE_STR
|
||||
#define UNKNOWN_RESP ((RADIO_RESP)UNKNOWN_VALUE)
|
||||
#define UNKNOWN_RESP_STR UNKNOWN_VALUE_STR
|
||||
#define INVALID_IND_TYPE ((RADIO_IND_TYPE)UNKNOWN_VALUE)
|
||||
|
||||
RadioInstance*
|
||||
radio_instance_get_with_interface(
|
||||
const char* dev,
|
||||
const char* name,
|
||||
RADIO_INTERFACE version); /* Deprecated and removed from the .h file */
|
||||
|
||||
gboolean
|
||||
radio_instance_is_dead(
|
||||
RadioInstance* self); /* No sure why this one is missing */
|
||||
|
||||
typedef struct test_radio_service {
|
||||
GBinderLocalObject* obj;
|
||||
GBinderRemoteObject* resp_obj;
|
||||
GBinderRemoteObject* ind_obj;
|
||||
GHashTable* req_count;
|
||||
} TestRadioService;
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
static const GBinderClientIfaceInfo radio_ind_iface_info[] = {
|
||||
{RADIO_INDICATION_1_4, RADIO_1_4_IND_LAST },
|
||||
{RADIO_INDICATION_1_3, RADIO_1_3_IND_LAST },
|
||||
{RADIO_INDICATION_1_2, RADIO_1_2_IND_LAST },
|
||||
{RADIO_INDICATION_1_1, RADIO_1_1_IND_LAST },
|
||||
{RADIO_INDICATION_1_0, RADIO_1_0_IND_LAST }
|
||||
};
|
||||
|
||||
static const GBinderClientIfaceInfo radio_resp_iface_info[] = {
|
||||
{RADIO_RESPONSE_1_4, RADIO_1_4_RESP_LAST },
|
||||
{RADIO_RESPONSE_1_3, RADIO_1_3_RESP_LAST },
|
||||
{RADIO_RESPONSE_1_2, RADIO_1_2_RESP_LAST },
|
||||
{RADIO_RESPONSE_1_1, RADIO_1_1_RESP_LAST },
|
||||
{RADIO_RESPONSE_1_0, RADIO_1_0_RESP_LAST }
|
||||
};
|
||||
|
||||
static const char* const radio_req_ifaces[] = {
|
||||
RADIO_1_4,
|
||||
RADIO_1_3,
|
||||
RADIO_1_2,
|
||||
RADIO_1_1,
|
||||
RADIO_1_0,
|
||||
NULL
|
||||
};
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_response_not_handled(
|
||||
RadioInstance* radio,
|
||||
RADIO_RESP code,
|
||||
const RadioResponseInfo* info,
|
||||
const GBinderReader* reader,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_response_not_observed(
|
||||
RadioInstance* radio,
|
||||
RADIO_RESP code,
|
||||
const RadioResponseInfo* info,
|
||||
const GBinderReader* reader,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Test IRadio service
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
int
|
||||
test_service_req_count(
|
||||
TestRadioService* service,
|
||||
RADIO_REQ req)
|
||||
{
|
||||
return GPOINTER_TO_INT(g_hash_table_lookup(service->req_count,
|
||||
GINT_TO_POINTER(req)));
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
test_service_txproc(
|
||||
GBinderLocalObject* obj,
|
||||
GBinderRemoteRequest* req,
|
||||
guint code,
|
||||
guint flags,
|
||||
int* status,
|
||||
void* user_data)
|
||||
{
|
||||
TestRadioService* service = user_data;
|
||||
const char* iface = gbinder_remote_request_interface(req);
|
||||
|
||||
if (gutil_strv_contains((const GStrV*)radio_req_ifaces, iface)) {
|
||||
const int count = test_service_req_count(service, code) + 1;
|
||||
GBinderReader reader;
|
||||
|
||||
GDEBUG("%s %s %d", iface, radio_req_name(code), count);
|
||||
g_hash_table_insert(service->req_count, GINT_TO_POINTER(code),
|
||||
GINT_TO_POINTER(count));
|
||||
|
||||
gbinder_remote_request_init_reader(req, &reader);
|
||||
switch (code) {
|
||||
case RADIO_REQ_SET_RESPONSE_FUNCTIONS:
|
||||
gbinder_remote_object_unref(service->resp_obj);
|
||||
gbinder_remote_object_unref(service->ind_obj);
|
||||
service->resp_obj = gbinder_reader_read_object(&reader);
|
||||
service->ind_obj = gbinder_reader_read_object(&reader);
|
||||
g_assert(service->resp_obj);
|
||||
g_assert(service->ind_obj);
|
||||
break;
|
||||
}
|
||||
*status = GBINDER_STATUS_OK;
|
||||
return NULL;
|
||||
} else {
|
||||
GDEBUG("%s %u", iface, code);
|
||||
*status = GBINDER_STATUS_FAILED;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_service_init(
|
||||
TestRadioService* service)
|
||||
{
|
||||
memset(service, 0, sizeof(*service));
|
||||
service->obj = test_gbinder_local_object_new(NULL,
|
||||
test_service_txproc, service);
|
||||
service->req_count = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_service_cleanup(
|
||||
TestRadioService* service)
|
||||
{
|
||||
g_hash_table_destroy(service->req_count);
|
||||
gbinder_remote_object_unref(service->resp_obj);
|
||||
gbinder_remote_object_unref(service->ind_obj);
|
||||
gbinder_local_object_unref(service->obj);
|
||||
memset(service, 0, sizeof(*service));
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* null
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_null(
|
||||
void)
|
||||
{
|
||||
radio_instance_set_enabled(NULL, FALSE);
|
||||
radio_instance_remove_handler(NULL, 0);
|
||||
radio_instance_remove_handlers(NULL, NULL, 0);
|
||||
radio_instance_unref(NULL);
|
||||
|
||||
g_assert(radio_instance_is_dead(NULL));
|
||||
|
||||
g_assert(!radio_instance_get(NULL, NULL));
|
||||
g_assert(!radio_instance_get("", NULL));
|
||||
g_assert(!radio_instance_get("/dev/binder", NULL));
|
||||
g_assert(!radio_instance_get("/dev/binder", ""));
|
||||
g_assert(!radio_instance_get_with_interface("", "", DEFAULT_INTERFACE));
|
||||
g_assert(!radio_instance_get_with_version("foo", "bar", DEFAULT_INTERFACE));
|
||||
g_assert(!radio_instance_new(NULL, NULL));
|
||||
g_assert(!radio_instance_new_with_modem_and_slot(NULL, NULL, NULL, 0));
|
||||
g_assert(!radio_instance_new_with_version(NULL, NULL, DEFAULT_INTERFACE));
|
||||
g_assert(!radio_instance_new_with_version(NULL, "", DEFAULT_INTERFACE));
|
||||
g_assert(!radio_instance_new_request(NULL, 0));
|
||||
g_assert(!radio_instance_ack(NULL));
|
||||
g_assert(!radio_instance_ref(NULL));
|
||||
g_assert(!radio_instance_send_request_sync(NULL, 0, NULL));
|
||||
g_assert(!radio_instance_add_indication_handler(NULL, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_indication_observer(NULL, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_response_handler(NULL, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_response_observer(NULL, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_ack_handler(NULL, NULL, NULL));
|
||||
g_assert(!radio_instance_add_death_handler(NULL, NULL, NULL));
|
||||
g_assert(!radio_instance_add_enabled_handler(NULL, NULL, NULL));
|
||||
g_assert(!radio_instance_req_name(NULL, UNKNOWN_REQ));
|
||||
g_assert(!radio_instance_resp_name(NULL, UNKNOWN_RESP));
|
||||
g_assert(!radio_instance_ind_name(NULL, UNKNOWN_IND));
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* basic
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_basic(
|
||||
void)
|
||||
{
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
RadioInstance* radio;
|
||||
RadioInstance* const* radios;
|
||||
TestRadioService service;
|
||||
const RADIO_INTERFACE version = RADIO_INTERFACE_1_4;
|
||||
const char* slot = "slot1";
|
||||
const char* fqname = RADIO_1_0 "/slot1";
|
||||
|
||||
/* This fails because there's no radio service */
|
||||
g_assert(!radio_instance_new_with_version(DEV, slot, DEFAULT_INTERFACE));
|
||||
g_assert(!radio_instance_get_all());
|
||||
|
||||
/* Register the service to create an instance */
|
||||
test_service_init(&service);
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, version);
|
||||
g_assert(radio);
|
||||
g_assert(service.ind_obj);
|
||||
g_assert(service.resp_obj);
|
||||
|
||||
/* The second call returns new reference to the same instance */
|
||||
g_assert(radio == radio_instance_new_with_version(DEV, slot, version));
|
||||
radio_instance_unref(radio);
|
||||
|
||||
/* The one we have created must still be there */
|
||||
g_assert(radio == radio_instance_get_with_version(DEV, slot, version));
|
||||
|
||||
/* NULL callbacks are ignored */
|
||||
g_assert(!radio_instance_add_indication_handler(radio, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_indication_observer(radio, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_response_handler(radio, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_response_observer(radio, 0, NULL, NULL));
|
||||
g_assert(!radio_instance_add_ack_handler(radio, NULL, NULL));
|
||||
g_assert(!radio_instance_add_death_handler(radio, NULL, NULL));
|
||||
g_assert(!radio_instance_add_enabled_handler(radio, NULL, NULL));
|
||||
|
||||
/* Formatting unknown codes (RadioInstance owns the string) */
|
||||
g_assert_cmpstr(radio_instance_req_name(radio, UNKNOWN_REQ), == ,
|
||||
UNKNOWN_REQ_STR);
|
||||
g_assert_cmpstr(radio_instance_resp_name(radio, UNKNOWN_RESP), == ,
|
||||
UNKNOWN_RESP_STR);
|
||||
g_assert_cmpstr(radio_instance_ind_name(radio, UNKNOWN_IND), == ,
|
||||
UNKNOWN_IND_STR);
|
||||
g_assert_cmpstr(radio_instance_req_name(radio,
|
||||
RADIO_REQ_DIAL), == ,"dial");
|
||||
g_assert_cmpstr(radio_instance_resp_name(radio,
|
||||
RADIO_RESP_DIAL), == ,"dialResponse");
|
||||
g_assert_cmpstr(radio_instance_ind_name(radio,
|
||||
RADIO_IND_MODEM_RESET), == ,"modemReset");
|
||||
|
||||
/* The entire list consists of that one instance */
|
||||
radios = radio_instance_get_all();
|
||||
g_assert(radios);
|
||||
g_assert(radios[0] == radio);
|
||||
g_assert(!radios[1]);
|
||||
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ind
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_ind_handle(
|
||||
RadioInstance* radio,
|
||||
RADIO_IND code,
|
||||
RADIO_IND_TYPE type,
|
||||
const GBinderReader* reader,
|
||||
gpointer user_data)
|
||||
{
|
||||
int* expected = user_data;
|
||||
|
||||
g_assert_cmpint(code, == ,*expected);
|
||||
*expected = RADIO_IND_NONE;
|
||||
radio_instance_ack(radio);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_ind_observe(
|
||||
RadioInstance* radio,
|
||||
RADIO_IND code,
|
||||
RADIO_IND_TYPE type,
|
||||
const GBinderReader* reader,
|
||||
gpointer user_data)
|
||||
{
|
||||
int* expected = user_data;
|
||||
|
||||
g_assert_cmpint(code, == ,*expected);
|
||||
*expected = RADIO_IND_NONE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_ind(
|
||||
void)
|
||||
{
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
RadioInstance* radio;
|
||||
TestRadioService service;
|
||||
GBinderClient* ind;
|
||||
GBinderLocalRequest* req;
|
||||
const RADIO_INTERFACE version = RADIO_INTERFACE_1_4;
|
||||
const char* slot = "slot1";
|
||||
const char* fqname = RADIO_1_0 "/slot1";
|
||||
int code[2];
|
||||
ulong id[2];
|
||||
|
||||
/* Register the service to create an instance */
|
||||
test_service_init(&service);
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, version);
|
||||
g_assert(radio);
|
||||
|
||||
/* Issue invalid indication (no type) */
|
||||
code[0] = code[1] = RADIO_IND_RIL_CONNECTED;
|
||||
id[0] = radio_instance_add_indication_handler(radio, RADIO_IND_RIL_CONNECTED,
|
||||
test_ind_handle, code + 0);
|
||||
id[1] = radio_instance_add_indication_observer(radio, RADIO_IND_ANY,
|
||||
test_ind_observe, code + 1);
|
||||
g_assert(service.ind_obj);
|
||||
ind = gbinder_client_new2(service.ind_obj,
|
||||
TEST_ARRAY_AND_COUNT(radio_ind_iface_info));
|
||||
req = gbinder_client_new_request2(ind, RADIO_IND_RIL_CONNECTED);
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
|
||||
RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_FAILED);
|
||||
|
||||
/* No signals issued and no acks sent */
|
||||
g_assert_cmpint(code[0], == ,RADIO_IND_RIL_CONNECTED);
|
||||
g_assert_cmpint(code[1], == ,RADIO_IND_RIL_CONNECTED);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,0);
|
||||
|
||||
/* Another invalid indication (invalid type) */
|
||||
gbinder_local_request_append_int32(req, INVALID_IND_TYPE);
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
|
||||
RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_FAILED);
|
||||
|
||||
/* No signals issued and no acks sent */
|
||||
g_assert_cmpint(code[0], == ,RADIO_IND_RIL_CONNECTED);
|
||||
g_assert_cmpint(code[0], == ,RADIO_IND_RIL_CONNECTED);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,0);
|
||||
|
||||
/* Build a valid request and try again */
|
||||
gbinder_local_request_unref(req);
|
||||
req = gbinder_client_new_request2(ind, RADIO_IND_RIL_CONNECTED);
|
||||
gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
|
||||
RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_OK);
|
||||
|
||||
/* This time both handler and observer are notified, ack is sent */
|
||||
g_assert_cmpint(code[0], == ,RADIO_IND_NONE);
|
||||
g_assert_cmpint(code[1], == ,RADIO_IND_NONE);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,1);
|
||||
|
||||
/* Now issue callStateChanged but only observe it (don't handle) */
|
||||
radio_instance_remove_handlers(radio, id, 1);
|
||||
code[1] = RADIO_IND_CALL_STATE_CHANGED;
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
|
||||
RADIO_IND_CALL_STATE_CHANGED, req), == ,GBINDER_STATUS_OK);
|
||||
g_assert_cmpint(code[1], == ,RADIO_IND_NONE);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Unhandled but acked */
|
||||
|
||||
/* Same thing but without ack */
|
||||
gbinder_local_request_unref(req);
|
||||
req = gbinder_client_new_request2(ind, RADIO_IND_CALL_STATE_CHANGED);
|
||||
gbinder_local_request_append_int32(req, RADIO_IND_UNSOLICITED);
|
||||
code[1] = RADIO_IND_CALL_STATE_CHANGED;
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
|
||||
RADIO_IND_CALL_STATE_CHANGED, req), == ,GBINDER_STATUS_OK);
|
||||
g_assert_cmpint(code[1], == ,RADIO_IND_NONE);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Still 2 (not acked) */
|
||||
|
||||
/* Unsupported interface */
|
||||
gbinder_local_request_unref(req);
|
||||
req = test_gbinder_local_request_new("foo");
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
|
||||
UNKNOWN_IND, req), == ,GBINDER_STATUS_FAILED);
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_client_unref(ind);
|
||||
|
||||
radio_instance_remove_all_handlers(radio, id);
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* req
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_REQ RADIO_REQ_DIAL
|
||||
|
||||
static
|
||||
void
|
||||
test_req(
|
||||
void)
|
||||
{
|
||||
const char* slot = "slot1";
|
||||
const char* fqname = RADIO_1_0 "/slot1";
|
||||
TestRadioService service;
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
GBinderLocalRequest* req;
|
||||
RadioInstance* radio;
|
||||
|
||||
test_service_init(&service);
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
|
||||
req = radio_instance_new_request(radio, TEST_REQ);
|
||||
gbinder_local_request_append_int32(req, 123);
|
||||
g_assert(radio_instance_send_request_sync(radio, TEST_REQ, req));
|
||||
g_assert_cmpint(test_service_req_count(&service, TEST_REQ), == ,1);
|
||||
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* resp
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_RESP RADIO_RESP_DIAL
|
||||
|
||||
static
|
||||
void
|
||||
test_resp_observe(
|
||||
RadioInstance* radio,
|
||||
RADIO_RESP code,
|
||||
const RadioResponseInfo* info,
|
||||
const GBinderReader* reader,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint* expected = user_data;
|
||||
|
||||
GDEBUG("Observing resp %u", code);
|
||||
g_assert_cmpuint(info->serial, == ,*expected);
|
||||
*expected = 0;
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
test_resp_handle(
|
||||
RadioInstance* radio,
|
||||
RADIO_RESP code,
|
||||
const RadioResponseInfo* info,
|
||||
const GBinderReader* reader,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint* expected = user_data;
|
||||
|
||||
GDEBUG("Handling resp %u", code);
|
||||
g_assert_cmpuint(info->serial, == ,*expected);
|
||||
*expected = 0;
|
||||
if (info->type == RADIO_RESP_SOLICITED_ACK_EXP) {
|
||||
radio_instance_ack(radio);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_resp(
|
||||
void)
|
||||
{
|
||||
const char* slot = "slot2";
|
||||
const char* fqname = RADIO_1_0 "/slot2";
|
||||
TestRadioService service;
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
GBinderLocalRequest* req;
|
||||
GBinderClient* resp;
|
||||
RadioInstance* radio;
|
||||
RadioResponseInfo info;
|
||||
GBinderWriter writer;
|
||||
guint handle_serial, observe_serial;
|
||||
gulong id[2];
|
||||
|
||||
test_service_init(&service);
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.type = RADIO_RESP_SOLICITED_ACK_EXP;
|
||||
handle_serial = observe_serial = info.serial = 123;
|
||||
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
|
||||
id[0] = radio_instance_add_response_handler(radio, TEST_RESP,
|
||||
test_resp_handle, &handle_serial);
|
||||
id[1] = radio_instance_add_response_observer(radio, TEST_RESP,
|
||||
test_resp_observe, &observe_serial);
|
||||
|
||||
g_assert(service.resp_obj);
|
||||
resp = gbinder_client_new2(service.resp_obj,
|
||||
TEST_ARRAY_AND_COUNT(radio_resp_iface_info));
|
||||
|
||||
/* Submit broken respose first (without info) */
|
||||
req = gbinder_client_new_request2(resp, TEST_RESP);
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
|
||||
== ,GBINDER_STATUS_OK);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,0);
|
||||
|
||||
/* Add the info and try again */
|
||||
gbinder_local_request_init_writer(req, &writer);
|
||||
gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
|
||||
== ,GBINDER_STATUS_OK);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,1);
|
||||
g_assert(!handle_serial); /* Cleared by the handler */
|
||||
g_assert(!observe_serial); /* Cleared by the observer */
|
||||
|
||||
/* Remove the handler and check auto-ack */
|
||||
radio_instance_remove_handlers(radio, id, 1);
|
||||
handle_serial = observe_serial = info.serial = 124;
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
|
||||
== ,GBINDER_STATUS_OK);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Acked */
|
||||
g_assert_cmpuint(handle_serial, == ,info.serial); /* No handler */
|
||||
g_assert(!observe_serial); /* Cleared by the observer */
|
||||
|
||||
/* RADIO_RESP_SOLICITED won't be acked */
|
||||
info.type = RADIO_RESP_SOLICITED;
|
||||
handle_serial = observe_serial = info.serial = 125;
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
|
||||
== ,GBINDER_STATUS_OK);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Not acked */
|
||||
g_assert_cmpuint(handle_serial, == ,info.serial); /* No handler */
|
||||
g_assert(!observe_serial); /* Cleared by the observer */
|
||||
|
||||
/* Unsupported interface */
|
||||
gbinder_local_request_unref(req);
|
||||
req = test_gbinder_local_request_new("foo");
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
|
||||
== ,GBINDER_STATUS_FAILED);
|
||||
g_assert_cmpint(test_service_req_count(&service,
|
||||
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Didn't change */
|
||||
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_client_unref(resp);
|
||||
|
||||
radio_instance_remove_all_handlers(radio, id);
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ack
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_ack_cb(
|
||||
RadioInstance* radio,
|
||||
guint32 serial,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint* expected = user_data;
|
||||
|
||||
GDEBUG("ack %u", serial);
|
||||
g_assert_cmpuint(serial, == ,*expected);
|
||||
*expected = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_ack(
|
||||
void)
|
||||
{
|
||||
const char* slot = "slot1";
|
||||
const char* fqname = RADIO_1_0 "/slot1";
|
||||
TestRadioService service;
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
GBinderLocalRequest* req;
|
||||
GBinderClient* resp;
|
||||
RadioInstance* radio;
|
||||
guint serial = 123;
|
||||
gulong id[3];
|
||||
|
||||
test_service_init(&service);
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
|
||||
id[0] = radio_instance_add_ack_handler(radio, test_ack_cb, &serial);
|
||||
id[1] = radio_instance_add_response_handler(radio, RADIO_RESP_ANY,
|
||||
test_response_not_handled, NULL);
|
||||
id[2] = radio_instance_add_response_observer(radio,
|
||||
RADIO_RESP_ACKNOWLEDGE_REQUEST, test_response_not_observed, NULL);
|
||||
|
||||
g_assert(service.resp_obj);
|
||||
resp = gbinder_client_new2(service.resp_obj,
|
||||
TEST_ARRAY_AND_COUNT(radio_resp_iface_info));
|
||||
|
||||
/* Submit broken ack first (without serial) */
|
||||
req = gbinder_client_new_request2(resp, RADIO_RESP_ACKNOWLEDGE_REQUEST);
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp,
|
||||
RADIO_RESP_ACKNOWLEDGE_REQUEST, req), == ,GBINDER_STATUS_OK);
|
||||
g_assert(serial); /* Transaction succeeds but handler is not called */
|
||||
|
||||
/* Add the serial and try again */
|
||||
gbinder_local_request_append_int32(req, serial);
|
||||
g_assert_cmpint(gbinder_client_transact_sync_oneway(resp,
|
||||
RADIO_RESP_ACKNOWLEDGE_REQUEST, req), == ,GBINDER_STATUS_OK);
|
||||
g_assert(!serial); /* Cleared by the handler */
|
||||
gbinder_local_request_unref(req);
|
||||
gbinder_client_unref(resp);
|
||||
|
||||
radio_instance_remove_all_handlers(radio, id);
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* enabled
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_enabled_cb(
|
||||
RadioInstance* radio,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDEBUG("%sabled", radio->enabled ? "En" : "Dis");
|
||||
(*((int*)user_data))++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_enabled(
|
||||
void)
|
||||
{
|
||||
const char* slot = "slot1";
|
||||
const char* fqname = RADIO_1_0 "/slot1";
|
||||
TestRadioService service;
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
RadioInstance* radio;
|
||||
int n = 0;
|
||||
gulong id;
|
||||
|
||||
test_service_init(&service);
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
|
||||
id = radio_instance_add_enabled_handler(radio, test_enabled_cb, &n);
|
||||
|
||||
g_assert(id);
|
||||
g_assert(!radio->enabled);
|
||||
radio_instance_set_enabled(radio, TRUE);
|
||||
g_assert_cmpint(n, == ,1);
|
||||
g_assert(radio->enabled);
|
||||
|
||||
radio_instance_set_enabled(radio, TRUE);
|
||||
g_assert(radio->enabled);
|
||||
g_assert_cmpint(n, == ,1); /* Nothing changed */
|
||||
|
||||
radio_instance_set_enabled(radio, FALSE);
|
||||
g_assert_cmpint(n, == ,2);
|
||||
g_assert(!radio->enabled);
|
||||
|
||||
radio_instance_remove_handler(radio, id);
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* death
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_death_cb(
|
||||
RadioInstance* radio,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDEBUG("Boom");
|
||||
(*((int*)user_data))++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_death(
|
||||
void)
|
||||
{
|
||||
const char* slot = "slot1";
|
||||
const char* fqname = RADIO_1_0 "/slot1";
|
||||
TestRadioService service;
|
||||
GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
|
||||
GBinderRemoteObject* remote;
|
||||
RadioInstance* radio;
|
||||
int n = 0;
|
||||
gulong id;
|
||||
|
||||
test_service_init(&service);
|
||||
remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
|
||||
radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
|
||||
id = radio_instance_add_death_handler(radio, test_death_cb, &n);
|
||||
|
||||
g_assert(id);
|
||||
g_assert(!radio_instance_is_dead(radio));
|
||||
test_gbinder_remote_object_kill(remote);
|
||||
g_assert_cmpint(n, == ,1);
|
||||
g_assert(radio_instance_is_dead(radio));
|
||||
|
||||
radio_instance_remove_handler(radio, 0); /* no effect */
|
||||
radio_instance_remove_handler(radio, id);
|
||||
radio_instance_unref(radio);
|
||||
test_service_cleanup(&service);
|
||||
gbinder_remote_object_unref(remote);
|
||||
gbinder_servicemanager_unref(sm);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Common
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/instance/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
g_test_add_func(TEST_("ind"), test_ind);
|
||||
g_test_add_func(TEST_("req"), test_req);
|
||||
g_test_add_func(TEST_("resp"), test_resp);
|
||||
g_test_add_func(TEST_("ack"), test_ack);
|
||||
g_test_add_func(TEST_("enabled"), test_enabled);
|
||||
g_test_add_func(TEST_("death"), test_death);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
5
unit/unit_registry/Makefile
Normal file
5
unit/unit_registry/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
EXE = unit_registry
|
||||
|
||||
include ../common/Makefile
|
||||
170
unit/unit_registry/unit_registry.c
Normal file
170
unit/unit_registry/unit_registry.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
#include "radio_instance.h"
|
||||
#include "radio_registry_p.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
/*==========================================================================*
|
||||
* null
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_null(
|
||||
void)
|
||||
{
|
||||
radio_registry_instance_added(NULL);
|
||||
radio_registry_instance_removed(NULL);
|
||||
radio_registry_remove_handler(NULL, 0);
|
||||
radio_registry_remove_handlers(NULL, NULL, 0);
|
||||
radio_registry_unref(NULL);
|
||||
g_assert(!radio_registry_ref(NULL));
|
||||
g_assert(!radio_registry_add_instance_added_handler(NULL,NULL,NULL,NULL));
|
||||
g_assert(!radio_registry_add_instance_removed_handler(NULL,NULL,NULL,NULL));
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* basic
|
||||
*==========================================================================*/
|
||||
|
||||
static const char* test_basic_key = "foo";
|
||||
static const char* test_basic_bad_key = "bar";
|
||||
|
||||
static
|
||||
void
|
||||
test_basic_add_cb(
|
||||
RadioRegistry* registry,
|
||||
RadioInstance* radio,
|
||||
gpointer user_data)
|
||||
{
|
||||
(*((int*)user_data))++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_basic_remove_cb(
|
||||
RadioRegistry* registry,
|
||||
const char* str,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert_cmpstr(str, == ,test_basic_key);
|
||||
(*((int*)user_data))++;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
test_basic(
|
||||
void)
|
||||
{
|
||||
RadioRegistry* reg = radio_registry_new();
|
||||
int add_count = 0, remove_count = 0;
|
||||
gulong id[6];
|
||||
GObject* instance;
|
||||
|
||||
g_assert(reg);
|
||||
g_assert(reg == radio_registry_new()); /* New ref to the same instance */
|
||||
radio_registry_unref(reg);
|
||||
|
||||
g_assert(!radio_registry_add_instance_added_handler(reg,NULL,NULL,NULL));
|
||||
g_assert(!radio_registry_add_instance_removed_handler(reg,NULL,NULL,NULL));
|
||||
|
||||
/* Add/remove handlers */
|
||||
id[0] = radio_registry_add_instance_added_handler(reg, "",
|
||||
test_basic_add_cb, &add_count);
|
||||
radio_registry_remove_handler(reg, id[0]);
|
||||
id[0] = radio_registry_add_instance_added_handler(reg, NULL,
|
||||
test_basic_add_cb, &add_count);
|
||||
id[1] = radio_registry_add_instance_added_handler(reg, test_basic_bad_key,
|
||||
test_basic_add_cb, &add_count); /* won't get called */
|
||||
|
||||
id[2] = radio_registry_add_instance_removed_handler(reg, NULL,
|
||||
test_basic_remove_cb, &remove_count);
|
||||
id[3] = radio_registry_add_instance_removed_handler(reg, "",
|
||||
test_basic_remove_cb, &remove_count);
|
||||
id[4] = radio_registry_add_instance_removed_handler(reg, test_basic_key,
|
||||
test_basic_remove_cb, &remove_count);
|
||||
id[5] = radio_registry_add_instance_removed_handler(reg, test_basic_bad_key,
|
||||
test_basic_remove_cb, &remove_count); /* won't get called */
|
||||
|
||||
/* Well, this wouldn't be a real functional instance but we don't care */
|
||||
instance = g_object_new(RADIO_TYPE_INSTANCE, NULL);
|
||||
radio_registry_instance_added(RADIO_INSTANCE(instance));
|
||||
g_assert_cmpint(add_count, == ,1); /* 1 out of 2 is called */
|
||||
g_assert_cmpint(remove_count, == ,0);
|
||||
|
||||
radio_registry_instance_removed(test_basic_key);
|
||||
g_assert_cmpint(add_count, == ,1);
|
||||
g_assert_cmpint(remove_count, == ,3); /* 3 our of 4 are called */
|
||||
g_object_unref(instance);
|
||||
|
||||
/* remove_all zeros the ids */
|
||||
radio_registry_remove_all_handlers(reg, id);
|
||||
g_assert(!id[0]);
|
||||
g_assert(!id[4]);
|
||||
|
||||
radio_registry_remove_handler(reg, 0); /* No effect */
|
||||
radio_registry_unref(reg);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Common
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/registry/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_("null"), test_null);
|
||||
g_test_add_func(TEST_("basic"), test_basic);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
5
unit/unit_util/Makefile
Normal file
5
unit/unit_util/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- Mode: makefile-gmake -*-
|
||||
|
||||
EXE = unit_util
|
||||
|
||||
include ../common/Makefile
|
||||
162
unit/unit_util/unit_util.c
Normal file
162
unit/unit_util/unit_util.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Jolla Ltd.
|
||||
* Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
|
||||
*
|
||||
* You may use this file under the terms of the BSD license as follows:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation
|
||||
* are those of the authors and should not be interpreted as representing
|
||||
* any official policies, either expressed or implied.
|
||||
*/
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
#include "radio_util.h"
|
||||
|
||||
#define UNKNOWN_VALUE (0x7fffffff)
|
||||
#define UNKNOWN_REQ ((RADIO_REQ)UNKNOWN_VALUE)
|
||||
#define UNKNOWN_IND ((RADIO_REQ)UNKNOWN_VALUE)
|
||||
#define UNKNOWN_RESP ((RADIO_RESP)UNKNOWN_VALUE)
|
||||
|
||||
static TestOpt test_opt;
|
||||
|
||||
/*==========================================================================*
|
||||
* req_name
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_req_name(
|
||||
void)
|
||||
{
|
||||
g_assert(!radio_req_name(UNKNOWN_REQ));
|
||||
g_assert(!radio_req_name(RADIO_REQ_ANY));
|
||||
g_assert_cmpstr(radio_req_name(RADIO_REQ_GET_ICC_CARD_STATUS),==,
|
||||
"getIccCardStatus");
|
||||
g_assert_cmpstr(radio_req_name(RADIO_REQ_START_NETWORK_SCAN),==,
|
||||
"startNetworkScan");
|
||||
g_assert_cmpstr(radio_req_name(RADIO_REQ_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
|
||||
"setSignalStrengthReportingCriteria");
|
||||
g_assert_cmpstr(radio_req_name(RADIO_REQ_SET_SYSTEM_SELECTION_CHANNELS),==,
|
||||
"setSystemSelectionChannels");
|
||||
g_assert_cmpstr(radio_req_name(RADIO_REQ_EMERGENCY_DIAL),==,
|
||||
"emergencyDial");
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* resp_name
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_resp_name(
|
||||
void)
|
||||
{
|
||||
g_assert(!radio_resp_name(UNKNOWN_RESP));
|
||||
g_assert(!radio_resp_name(RADIO_RESP_ANY));
|
||||
g_assert_cmpstr(radio_resp_name(RADIO_RESP_GET_ICC_CARD_STATUS),==,
|
||||
"getIccCardStatusResponse");
|
||||
g_assert_cmpstr(radio_resp_name(RADIO_RESP_START_NETWORK_SCAN),==,
|
||||
"startNetworkScanResponse");
|
||||
g_assert_cmpstr(radio_resp_name(RADIO_RESP_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
|
||||
"setSignalStrengthReportingCriteriaResponse");
|
||||
g_assert_cmpstr(radio_resp_name(RADIO_RESP_SET_SYSTEM_SELECTION_CHANNELS),==,
|
||||
"setSystemSelectionChannelsResponse");
|
||||
g_assert_cmpstr(radio_resp_name(RADIO_RESP_EMERGENCY_DIAL),==,
|
||||
"emergencyDialResponse");
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* ind_name
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_ind_name(
|
||||
void)
|
||||
{
|
||||
g_assert(!radio_ind_name(UNKNOWN_IND));
|
||||
g_assert(!radio_ind_name(RADIO_IND_ANY));
|
||||
g_assert_cmpstr(radio_ind_name(RADIO_IND_RADIO_STATE_CHANGED),==,
|
||||
"radioStateChanged");
|
||||
g_assert_cmpstr(radio_ind_name(RADIO_IND_NETWORK_SCAN_RESULT),==,
|
||||
"networkScanResult");
|
||||
g_assert_cmpstr(radio_ind_name(RADIO_IND_CURRENT_LINK_CAPACITY_ESTIMATE),==,
|
||||
"currentLinkCapacityEstimate");
|
||||
g_assert_cmpstr(radio_ind_name(RADIO_IND_CURRENT_EMERGENCY_NUMBER_LIST),==,
|
||||
"currentEmergencyNumberList");
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* req_resp
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
test_req_resp(
|
||||
void)
|
||||
{
|
||||
g_assert_cmpint(radio_req_resp(UNKNOWN_REQ), == ,RADIO_RESP_NONE);
|
||||
g_assert_cmpint(radio_req_resp(RADIO_REQ_ANY), == ,RADIO_RESP_NONE);
|
||||
g_assert_cmpint(radio_req_resp(RADIO_REQ_GET_ICC_CARD_STATUS),==,
|
||||
RADIO_RESP_GET_ICC_CARD_STATUS);
|
||||
g_assert_cmpint(radio_req_resp(RADIO_REQ_START_NETWORK_SCAN),==,
|
||||
RADIO_RESP_START_NETWORK_SCAN);
|
||||
g_assert_cmpint(radio_req_resp(RADIO_REQ_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
|
||||
RADIO_RESP_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA);
|
||||
g_assert_cmpint(radio_req_resp(RADIO_REQ_SET_SYSTEM_SELECTION_CHANNELS),==,
|
||||
RADIO_RESP_SET_SYSTEM_SELECTION_CHANNELS);
|
||||
g_assert_cmpint(radio_req_resp(RADIO_REQ_EMERGENCY_DIAL),==,
|
||||
RADIO_RESP_EMERGENCY_DIAL);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Common
|
||||
*==========================================================================*/
|
||||
|
||||
#define TEST_PREFIX "/util/"
|
||||
#define TEST_(t) TEST_PREFIX t
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func(TEST_("req_name"), test_req_name);
|
||||
g_test_add_func(TEST_("resp_name"), test_resp_name);
|
||||
g_test_add_func(TEST_("ind_name"), test_ind_name);
|
||||
g_test_add_func(TEST_("req_resp"), test_req_resp);
|
||||
test_init(&test_opt, argc, argv);
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user