/*
 * Copyright 2020-2021 Stefan Ott
 *
 * This file is part of warmluft.
 *
 * Warmluft is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Foobar is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Foobar.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <stdlib.h>

#include <CUnit/Basic.h>
#include <CUnit/Automated.h>

#include "hwmon.h"

extern int sensor_field_name(struct hwmon_sensor *, char *, char *, size_t);
extern int is_temp_input(const char *);
extern int temp_input_max_name(const char *, char *buf, size_t len);

static void
test_temp_sensor_name()
{
	CU_ASSERT_FALSE(is_temp_input(""));
	CU_ASSERT_FALSE(is_temp_input("bla"));
	CU_ASSERT_FALSE(is_temp_input("in2_alarm"));
	CU_ASSERT_FALSE(is_temp_input("in6_input"));
	CU_ASSERT_FALSE(is_temp_input("temp1_beep"));
	CU_ASSERT_FALSE(is_temp_input("temp2_type"));
	CU_ASSERT_FALSE(is_temp_input("temp_input"));

	CU_ASSERT_TRUE(is_temp_input("temp1_input"));
	CU_ASSERT_TRUE(is_temp_input("temp2_input"));
	CU_ASSERT_TRUE(is_temp_input("temp231_input"));
}

static void
test_sensor_field_name()
{
	 char buf[256];
	 struct hwmon_sensor s;
	 int res;

	 memset(buf, 0, sizeof(buf));
	 snprintf(s.path_in, sizeof(s.path_in), "temp1");
	 res = sensor_field_name(&s, "_max", buf, sizeof(buf));
	 CU_ASSERT_EQUAL(res, 1);
	 CU_ASSERT_STRING_EQUAL(buf, "");
	 CU_ASSERT_STRING_EQUAL(s.path_in, "temp1");

	 memset(buf, 0, sizeof(buf));
	 snprintf(s.path_in, sizeof(s.path_in), "temp1");
	 res = sensor_field_name(&s, "_max", buf, sizeof(buf));
	 CU_ASSERT_EQUAL(res, 1);
	 CU_ASSERT_STRING_EQUAL(buf, "");
	 CU_ASSERT_STRING_EQUAL(s.path_in, "temp1");

	 memset(buf, 0, sizeof(buf));
	 snprintf(s.path_in, sizeof(s.path_in), "temp1_input");
	 res = sensor_field_name(&s, "_max", buf, sizeof(buf));
	 CU_ASSERT_EQUAL(res, 0);
	 CU_ASSERT_STRING_EQUAL(buf, "temp1_max");
	 CU_ASSERT_STRING_EQUAL(s.path_in, "temp1_input");

	 memset(buf, 0, sizeof(buf));
	 snprintf(s.path_in, sizeof(s.path_in), "temp1_input");
	 res = sensor_field_name(&s, "_max", buf, sizeof(buf));
	 CU_ASSERT_EQUAL(res, 0);
	 CU_ASSERT_STRING_EQUAL(buf, "temp1_max");
	 CU_ASSERT_STRING_EQUAL(s.path_in, "temp1_input");
}

static int
test_temp_input_names()
{
	CU_pSuite suite;

	suite = CU_add_suite("Temperature sensor name", NULL, NULL);
	if (suite == NULL)
	{
		return 1;
	}

	if (!CU_add_test(suite, "Test sensor name",
				test_temp_sensor_name)
		|| !CU_add_test(suite, "Test max name",
				test_sensor_field_name)
	)
	{
		return 1;
	}

	return 0;
}

static struct hwmon_device *
setup_test_devices()
{
	struct hwmon_device *d1, *d2;
	struct hwmon_sensor *s1, *s2, *s3, *s4, *s5;

	d1 = malloc(sizeof(struct hwmon_device));
	d2 = malloc(sizeof(struct hwmon_device));

	memset(d1, 0, sizeof(struct hwmon_device));
	memset(d2, 0, sizeof(struct hwmon_device));

	d1->next = d2;

	snprintf(d1->path, sizeof(d1->path), "/sys/class/hwmon/hwmon0");
	snprintf(d2->path, sizeof(d2->path), "/sys/class/hwmon/hwmon1");

	s1 = malloc(sizeof(struct hwmon_sensor));
	s2 = malloc(sizeof(struct hwmon_sensor));
	s3 = malloc(sizeof(struct hwmon_sensor));
	s4 = malloc(sizeof(struct hwmon_sensor));
	s5 = malloc(sizeof(struct hwmon_sensor));

	memset(s1, 0, sizeof(struct hwmon_sensor));
	memset(s2, 0, sizeof(struct hwmon_sensor));
	memset(s3, 0, sizeof(struct hwmon_sensor));
	memset(s4, 0, sizeof(struct hwmon_sensor));
	memset(s5, 0, sizeof(struct hwmon_sensor));

	d1->sensors = s1;
	s1->device = d1;
	s2->device = d1;
	s3->device = d1;
	s1->next = s2;
	s2->next = s3;

	d2->sensors = s4;
	s4->device = d2;
	s5->device = d2;
	s4->next = s5;

	snprintf(s1->path_in, sizeof(s1->path_in), "temp1_input");
	snprintf(s2->path_in, sizeof(s2->path_in), "temp2_input");
	snprintf(s3->path_in, sizeof(s3->path_in), "temp3_input");
	snprintf(s4->path_in, sizeof(s4->path_in), "temp1_input");
	snprintf(s5->path_in, sizeof(s5->path_in), "temp4_input");

	return d1;
}

static void
test_find_device_list_empty()
{
	struct hwmon_sensor *dev;

	dev = hwmon_dev_by_path(NULL, "/sys/class/hwmon/hwmon1/temp1_input");
	CU_ASSERT_PTR_NULL(dev);
}

static void
test_find_no_such_device()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon2/temp1_input");
	CU_ASSERT_PTR_NULL(s);

	hwmon_free_devices(all);
}

static void
test_find_no_such_sensor()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon1/temp2_input");
	CU_ASSERT_PTR_NULL(s);

	hwmon_free_devices(all);
}

static void
test_find_first_sensor_first_device()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon0/temp1_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s);
	CU_ASSERT_STRING_EQUAL(s->path_in, "temp1_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s->device);
	CU_ASSERT_STRING_EQUAL(s->device->path, "/sys/class/hwmon/hwmon0");

	hwmon_free_devices(all);
}

static void
test_find_second_sensor_first_device()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon0/temp2_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s);
	CU_ASSERT_STRING_EQUAL(s->path_in, "temp2_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s->device);
	CU_ASSERT_STRING_EQUAL(s->device->path, "/sys/class/hwmon/hwmon0");

	hwmon_free_devices(all);
}

static void
test_find_third_sensor_first_device()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon0/temp3_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s);
	CU_ASSERT_STRING_EQUAL(s->path_in, "temp3_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s->device);
	CU_ASSERT_STRING_EQUAL(s->device->path, "/sys/class/hwmon/hwmon0");

	hwmon_free_devices(all);
}

static void
test_find_first_sensor_second_device()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon1/temp1_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s);
	CU_ASSERT_STRING_EQUAL(s->path_in, "temp1_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s->device);
	CU_ASSERT_STRING_EQUAL(s->device->path, "/sys/class/hwmon/hwmon1");

	hwmon_free_devices(all);
}

static void
test_find_second_sensor_second_device()
{
	struct hwmon_device *all;
	struct hwmon_sensor *s;

	all = setup_test_devices();
	s = hwmon_dev_by_path(all, "/sys/class/hwmon/hwmon1/temp4_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s);
	CU_ASSERT_STRING_EQUAL(s->path_in, "temp4_input");

	CU_ASSERT_PTR_NOT_NULL_FATAL(s->device);
	CU_ASSERT_STRING_EQUAL(s->device->path, "/sys/class/hwmon/hwmon1");

	hwmon_free_devices(all);
}

static int
test_find_device_by_path()
{
	CU_pSuite suite;

	suite = CU_add_suite("Find device by path", NULL, NULL);
	if (suite == NULL)
	{
		return 1;
	}

	if (!CU_add_test(suite, "Find device in empty list",
				test_find_device_list_empty)
		|| !CU_add_test(suite, "Find sensor in unknown device",
				test_find_no_such_device)
		|| !CU_add_test(suite, "Find unknown sensor in known device",
				test_find_no_such_sensor)
		|| !CU_add_test(suite, "First sensor in first device",
				test_find_first_sensor_first_device)
		|| !CU_add_test(suite, "Second sensor in first device",
				test_find_second_sensor_first_device)
		|| !CU_add_test(suite, "Third sensor in first device",
				test_find_third_sensor_first_device)
		|| !CU_add_test(suite, "First sensor in second device",
				test_find_first_sensor_second_device)
		|| !CU_add_test(suite, "Second sensor in second device",
				test_find_second_sensor_second_device)
	)
	{
		return 1;
	}

	return 0;
}

static void
test_find_best_nodev()
{
	CU_ASSERT_PTR_NULL(hwmon_best_sensor(NULL));
}

static void
test_find_best_nosensor()
{
	struct hwmon_device d1, d2;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	d1.next = &d2;

	CU_ASSERT_PTR_NULL(hwmon_best_sensor(&d1));
}

static void
test_find_best_onlyone_first_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	d1.sensors = &s1;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
}

static void
test_find_best_onlyone_second_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	d2.sensors = &s1;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
}

static void
test_find_best_onlyone_last_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	d3.sensors = &s1;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
}

static void
test_best_is_only_sensor_on_first_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1, s2, s3, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	memset(&s2, 0, sizeof(struct hwmon_sensor));
	memset(&s3, 0, sizeof(struct hwmon_sensor));

	d1.sensors = &s1;
	d2.sensors = &s2;
	d3.sensors = &s3;
	s1.device = &d1;
	s2.device = &d2;
	s3.device = &d3;

	s1.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
}

static void
test_best_is_only_sensor_on_second_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1, s2, s3, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	memset(&s2, 0, sizeof(struct hwmon_sensor));
	memset(&s3, 0, sizeof(struct hwmon_sensor));

	d1.sensors = &s1;
	d2.sensors = &s2;
	d3.sensors = &s3;
	s1.device = &d1;
	s2.device = &d2;
	s3.device = &d3;

	s2.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
}

static void
test_best_is_only_sensor_on_last_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1, s2, s3, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	memset(&s2, 0, sizeof(struct hwmon_sensor));
	memset(&s3, 0, sizeof(struct hwmon_sensor));

	d1.sensors = &s1;
	d2.sensors = &s2;
	d3.sensors = &s3;
	s1.device = &d1;
	s2.device = &d2;
	s3.device = &d3;

	s3.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s3);
}

static void
test_best_is_first_sensor_on_first_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1a, s2a, s2b, s3a, s3b, s3c, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1a, 0, sizeof(struct hwmon_sensor));
	memset(&s2a, 0, sizeof(struct hwmon_sensor));
	memset(&s2b, 0, sizeof(struct hwmon_sensor));
	memset(&s3a, 0, sizeof(struct hwmon_sensor));
	memset(&s3b, 0, sizeof(struct hwmon_sensor));
	memset(&s3c, 0, sizeof(struct hwmon_sensor));
	s2a.next = &s2b;
	s3a.next = &s3b;
	s3b.next = &s3c;

	d1.sensors = &s1a;
	d2.sensors = &s2a;
	d3.sensors = &s3a;
	s1a.device = &d1;
	s2a.device = &d2;
	s2b.device = &d2;
	s3a.device = &d3;
	s3b.device = &d3;
	s3c.device = &d3;

	s1a.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1a);
}

static void
test_best_is_second_sensor_on_second_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1a, s2a, s2b, s3a, s3b, s3c, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1a, 0, sizeof(struct hwmon_sensor));
	memset(&s2a, 0, sizeof(struct hwmon_sensor));
	memset(&s2b, 0, sizeof(struct hwmon_sensor));
	memset(&s3a, 0, sizeof(struct hwmon_sensor));
	memset(&s3b, 0, sizeof(struct hwmon_sensor));
	memset(&s3c, 0, sizeof(struct hwmon_sensor));
	s2a.next = &s2b;
	s3a.next = &s3b;
	s3b.next = &s3c;

	d1.sensors = &s1a;
	d2.sensors = &s2a;
	d3.sensors = &s3a;
	s1a.device = &d1;
	s2a.device = &d2;
	s2b.device = &d2;
	s3a.device = &d3;
	s3b.device = &d3;
	s3c.device = &d3;

	s2b.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2b);
}

static void
test_best_is_last_sensor_on_last_dev()
{
	struct hwmon_device d1, d2, d3;
	struct hwmon_sensor s1a, s2a, s2b, s3a, s3b, s3c, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	memset(&d3, 0, sizeof(struct hwmon_device));
	d1.next = &d2;
	d2.next = &d3;

	memset(&s1a, 0, sizeof(struct hwmon_sensor));
	memset(&s2a, 0, sizeof(struct hwmon_sensor));
	memset(&s2b, 0, sizeof(struct hwmon_sensor));
	memset(&s3a, 0, sizeof(struct hwmon_sensor));
	memset(&s3b, 0, sizeof(struct hwmon_sensor));
	memset(&s3c, 0, sizeof(struct hwmon_sensor));
	s2a.next = &s2b;
	s3a.next = &s3b;
	s3b.next = &s3c;

	d1.sensors = &s1a;
	d2.sensors = &s2a;
	d3.sensors = &s3a;
	s1a.device = &d1;
	s2a.device = &d2;
	s2b.device = &d2;
	s3a.device = &d3;
	s3b.device = &d3;
	s3c.device = &d3;

	s3c.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s3c);
}

static void
test_prefer_sensor_with_max_temp()
{
	struct hwmon_device d1;
	struct hwmon_sensor s1, s2, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	d1.sensors = &s1;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	memset(&s2, 0, sizeof(struct hwmon_sensor));
	s1.next = &s2;
	s1.device = &d1;
	s2.device = &d1;

	s1.temp_max = 25;
	s2.temp_max = 0;
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);

	s1.temp_max = 0;
	s2.temp_max = 25;
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
}

static void
test_prefer_coretemp()
{
	struct hwmon_device d1, d2;
	struct hwmon_sensor s1, s2, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	d1.next = &d2;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	memset(&s2, 0, sizeof(struct hwmon_sensor));

	d1.sensors = &s1;
	s1.device = &d1;
	d2.sensors = &s2;
	s2.device = &d2;

	snprintf(d1.name, sizeof(d1.name), "coretemp");
	snprintf(d2.name, sizeof(d2.name), "something else");

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);

	snprintf(d1.name, sizeof(d2.name), "something else");
	snprintf(d2.name, sizeof(d1.name), "coretemp");
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
}

static void
test_prefer_coretemp_over_sensor_with_max_value()
{
	struct hwmon_device d1, d2;
	struct hwmon_sensor s1, s2, *best;

	memset(&d1, 0, sizeof(struct hwmon_device));
	memset(&d2, 0, sizeof(struct hwmon_device));
	d1.next = &d2;

	memset(&s1, 0, sizeof(struct hwmon_sensor));
	memset(&s2, 0, sizeof(struct hwmon_sensor));

	d1.sensors = &s1;
	s1.device = &d1;
	d2.sensors = &s2;
	s2.device = &d2;

	snprintf(d1.name, sizeof(d1.name), "coretemp");
	snprintf(d2.name, sizeof(d2.name), "something else");
	s1.temp_max = 0;
	s2.temp_max = 25;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s1);

	snprintf(d1.name, sizeof(d2.name), "something else");
	snprintf(d2.name, sizeof(d1.name), "coretemp");
	s1.temp_max = 25;
	s2.temp_max = 0;

	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
	best = hwmon_best_sensor(&d1);
	CU_ASSERT_EQUAL(best, &s2);
}

static int
test_find_best_device()
{
	CU_pSuite suite;

	suite = CU_add_suite("Find best sensor", NULL, NULL);
	if (suite == NULL)
	{
		return 1;
	}

	if (!CU_add_test(suite, "No devices",
				test_find_best_nodev)
		|| !CU_add_test(suite, "No sensors",
				test_find_best_nosensor)
		|| !CU_add_test(suite, "Only one sensor, first device",
				test_find_best_onlyone_first_dev)
		|| !CU_add_test(suite, "Only one sensor, second device",
				test_find_best_onlyone_second_dev)
		|| !CU_add_test(suite, "Only one sensor, last device",
				test_find_best_onlyone_last_dev)
		|| !CU_add_test(suite, "Best is only sensor on first device",
				test_best_is_only_sensor_on_first_dev)
		|| !CU_add_test(suite, "Best is only sensor on second device",
				test_best_is_only_sensor_on_second_dev)
		|| !CU_add_test(suite, "Best is only sensor on last device",
				test_best_is_only_sensor_on_last_dev)
		|| !CU_add_test(suite, "Best is first sensor on first device",
				test_best_is_first_sensor_on_first_dev)
		|| !CU_add_test(suite, "Best is second sensor on second device",
				test_best_is_second_sensor_on_second_dev)
		|| !CU_add_test(suite, "Best is last sensor on last device",
				test_best_is_last_sensor_on_last_dev)
		|| !CU_add_test(suite, "Prefer sensor with a max temperature",
				test_prefer_sensor_with_max_temp)
		|| !CU_add_test(suite, "Prefer coretemp sensor",
				test_prefer_coretemp)
		|| !CU_add_test(suite, "Coretemp beats max temperature",
				test_prefer_coretemp_over_sensor_with_max_value)
	)
	{
		return 1;
	}

	return 0;
}

int
main()
{
	int res;

	/* Initialize the CUnit test registry */	
	if (CU_initialize_registry() != CUE_SUCCESS)
	{
		return CU_get_error();
	}

	/* Add suites to the registry */
	if (test_temp_input_names()
		|| test_find_device_by_path()
		|| test_find_best_device())
	{
		CU_cleanup_registry();
		return CU_get_error();
	}

	/* Run the tests */
	CU_basic_set_mode(CU_BRM_VERBOSE);
	CU_basic_run_tests();

	printf("\n");
	CU_basic_show_failures(CU_get_failure_list());
	printf("\n");

	res = CU_get_number_of_failure_records();
	CU_cleanup_registry();

	return res;
}
