#include <gio/gio.h>

#include "unity-webapps-indicator-model.h"

typedef struct _IndicatorModelTestFixture {
  UnityWebappsIndicatorModel *indicator_model;
} IndicatorModelTestFixture;


static void
setup_fixture (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  fixture->indicator_model = unity_webapps_indicator_model_new ();
}

static gchar *
print_indicator_model (IndicatorModelTestFixture *fixture)
{
  GVariant *serialized_variant;
  gchar *serialized_string;
  
  serialized_variant = unity_webapps_indicator_model_serialize (fixture->indicator_model);
  serialized_string = g_variant_print (serialized_variant, FALSE);
  
  g_variant_unref (serialized_variant);
  return serialized_string;
}

static void
assert_indicator_model_equal (IndicatorModelTestFixture *fixture, const gchar *compare_to)
{
  gchar *serialized_model;
  
  serialized_model = print_indicator_model (fixture);
  
  g_assert_cmpstr(serialized_model, ==, compare_to);

  g_free (serialized_model);
}

#define SINGLE_INTEREST_TEST1_SERIALIZED "([('Foo', 1, {})],)"

static void
test_single_interest_test1 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  assert_indicator_model_equal (fixture, SINGLE_INTEREST_TEST1_SERIALIZED);
}

#define SINGLE_INTEREST_TEST2_SERIALIZED "([('Bar', 1, {}), ('Foo', 1, {})],)"

static void
test_single_interest_test2 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 1);
  assert_indicator_model_equal (fixture, SINGLE_INTEREST_TEST2_SERIALIZED);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model, 
							      "Bar", 1);
  
  assert_indicator_model_equal (fixture, SINGLE_INTEREST_TEST1_SERIALIZED);
}

#define SINGLE_INTEREST_TEST3_SERIALIZED "([('Bar', 1, {}), ('Baz', 1, {}), ('Foo', 1, {})],)"
#define EMPTY_INDICATOR_MODEL "([],)"

static void
test_single_interest_test3 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Baz", 1);
  assert_indicator_model_equal (fixture, SINGLE_INTEREST_TEST3_SERIALIZED);
  
  unity_webapps_indicator_model_clear_indicators_for_interest (fixture->indicator_model, 1);
  
  assert_indicator_model_equal (fixture, EMPTY_INDICATOR_MODEL);
}

#define SINGLE_INTEREST_PROPERTY_TEST1_SERIALIZED "([('Foo', 1, {'count': <3>})],)"
static void
test_single_interest_property_test1 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "count", g_variant_new("i", 3), 1);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST1_SERIALIZED);
}

#define SINGLE_INTEREST_PROPERTY_TEST2_SERIALIZED "([('Foo', 1, {'count': <3>, 'date': <1>})],)"
#define SINGLE_INTEREST_PROPERTY_TEST2_0_SERIALIZED "([('Foo', 1, {'count': <3>, 'date': <2>})],)"
static void
test_single_interest_property_test2 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "count", g_variant_new("i", 3), 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "date", g_variant_new("i", 1), 1);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST2_SERIALIZED);

  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "date", g_variant_new("i", 2), 1);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST2_0_SERIALIZED);
}

#define SINGLE_INTEREST_PROPERTY_TEST4_SERIALIZED "([('Foo', 1, {'count': <3>, 'date': <1>})],)"
#define SINGLE_INTEREST_PROPERTY_TEST4_0_SERIALIZED "([],)"
static void
test_single_interest_property_test4 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "count", g_variant_new("i", 3), 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "date", g_variant_new("i", 1), 1);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST4_SERIALIZED);

  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model, "Foo",
							      1);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST4_0_SERIALIZED);
}

#define SINGLE_INTEREST_PROPERTY_TEST3_SERIALIZED "([('Foo', 1, {'count': <3>, 'date': <1>})],)"
static void
test_single_interest_property_test3 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "count", g_variant_new("i", 3), 1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "date", g_variant_new("i", 1), 1);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST3_SERIALIZED);

  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model, "Foo",
								       "date", g_variant_new("i", 2), 2);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_PROPERTY_TEST3_SERIALIZED);
}

#define MULTI_INTEREST_TEST1_SERIALIZED "([('Bar', 1, {}), ('Foo', 1, {})],)"
static void
test_multi_interest_test1 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 2);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST1_SERIALIZED);
}

#define MULTI_INTEREST_TEST2_SERIALIZED "([('Foo', 2, {})],)"
static void
test_multi_interest_test2 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST2_SERIALIZED);
}

#define MULTI_INTEREST_TEST3_SERIALIZED "([('Foo', 2, {})],)"
static void
test_multi_interest_test3 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);

  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST3_SERIALIZED);
}

#define MULTI_INTEREST_TEST4_SERIALIZED "([('Bar', 1, {}), ('Foo', 1, {})],)"
static void
test_multi_interest_test4 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 2);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Baz", 2);

  assert_indicator_model_equal (fixture, SINGLE_INTEREST_TEST3_SERIALIZED);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model,
							      "Baz", 2);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST4_SERIALIZED);
}

#define MULTI_INTEREST_TEST5_SERIALIZED "([('Bar', 2, {}), ('Foo', 1, {})],)"
#define MULTI_INTEREST_TEST5_0_SERIALIZED "([('Bar', 1, {}), ('Foo', 1, {})],)"
static void
test_multi_interest_test5 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 2);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 1);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST5_SERIALIZED);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model,
							      "Bar", 1);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST5_0_SERIALIZED);
}

#define MULTI_INTEREST_TEST6_SERIALIZED "([('Bar', 2, {}), ('Foo', 1, {})],)"
#define MULTI_INTEREST_TEST6_0_SERIALIZED "([('Bar', 1, {}), ('Foo', 1, {})],)"
static void
test_multi_interest_test6 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 2);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 1);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST6_SERIALIZED);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model,
							      "Bar", 1);
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model,
							      "Bar", 1);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST6_0_SERIALIZED);
}

#define MULTI_INTEREST_TEST7_SERIALIZED "([('Bar', 2, {}), ('Foo', 1, {})],)"
#define MULTI_INTEREST_TEST7_0_SERIALIZED "([('Foo', 1, {})],)"
static void
test_multi_interest_test7 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 2);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Bar", 1);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST7_SERIALIZED);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model,
							      "Bar", 1);
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model,
							      "Bar", 2);
  
  assert_indicator_model_equal (fixture, MULTI_INTEREST_TEST7_0_SERIALIZED);
}

#define MULTI_INTEREST_PROPERTY_TEST1_SERIALIZED "([('Foo', 2, {'label': <4>})],)"
static void
test_multi_interest_property_test1 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);

  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 3),
								     1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 4),
								     2);

  assert_indicator_model_equal (fixture, MULTI_INTEREST_PROPERTY_TEST1_SERIALIZED);
}


#define MULTI_INTEREST_PROPERTY_TEST2_SERIALIZED "([('Foo', 1, {'label': <3>})],)"
static void
test_multi_interest_property_test2 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);

  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 3),
								     1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 4),
								     2);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model, 
							      "Foo", 2);

  assert_indicator_model_equal (fixture, MULTI_INTEREST_PROPERTY_TEST2_SERIALIZED);
}

#define MULTI_INTEREST_PROPERTY_TEST3_SERIALIZED "([('Foo', 1, {'label': <4>})],)"
static void
test_multi_interest_property_test3 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);

  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 3),
								     1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 4),
								     2);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model, 
							      "Foo", 1);

  assert_indicator_model_equal (fixture, MULTI_INTEREST_PROPERTY_TEST3_SERIALIZED);
}

#define MULTI_INTEREST_PROPERTY_TEST4_SERIALIZED "([('Foo', 1, {'label': <3>})],)"
static void
test_multi_interest_property_test4 (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 2);

  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 3),
								     1);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 4),
								     2);
  unity_webapps_indicator_model_set_indicator_property_for_interest (fixture->indicator_model,
								     "Foo",
								     "label", g_variant_new ("i", 5),
								     2);
  
  unity_webapps_indicator_model_clear_indicator_for_interest (fixture->indicator_model, 
							      "Foo", 2);

  assert_indicator_model_equal (fixture, MULTI_INTEREST_PROPERTY_TEST4_SERIALIZED);
}

static void
test_invalid_property_reads (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  g_assert (unity_webapps_indicator_model_get_indicator_property (fixture->indicator_model, "Foo", "Bar") == NULL);
  unity_webapps_indicator_model_show_indicator_for_interest (fixture->indicator_model,
							     "Foo", 1);
  g_assert (unity_webapps_indicator_model_get_indicator_property (fixture->indicator_model, "Foo", "Bar") == NULL);

}


static void
teardown_fixture (IndicatorModelTestFixture *fixture, gconstpointer user_data)
{
  g_object_unref (G_OBJECT (fixture->indicator_model));
}

int 
main (int argc, char **argv)
{
  g_type_init ();
  g_test_init (&argc, &argv, NULL);
  
  g_test_add("/SingleInterest/ShowIndicator", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_test1, teardown_fixture);
  g_test_add("/SingleInterest/ClearIndicator", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_test2, teardown_fixture);
  g_test_add("/SingleInterest/ClearAllIndicators", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_test3, teardown_fixture);
  g_test_add("/SingleInterest/Properties/UpdateProperties", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_property_test2, teardown_fixture);
  g_test_add("/SingleInterest/Properties/UpdatePropertiesRemoveInterest", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_property_test4, teardown_fixture);
  g_test_add("/SingleInterest/Properties/SetProperty", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_property_test1, teardown_fixture);
  g_test_add("/SingleInterest/Properties/UpdatePropertyNoShow", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_single_interest_property_test3, teardown_fixture);
  g_test_add("/MultiInterest/ShowIndicator/Scenario1",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test1, teardown_fixture);
  g_test_add("/MultiInterest/ShowIndicator/Scenario2",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test2, teardown_fixture);
  g_test_add("/MultiInterest/ShowIndicator/Scenario3",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test3, teardown_fixture);
  g_test_add("/MultiInterest/ClearIndicator/Scenario1",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test4, teardown_fixture);
  g_test_add("/MultiInterest/ClearIndicator/Scenario2",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test5, teardown_fixture);
  g_test_add("/MultiInterest/ClearIndicator/Scenario3",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test6, teardown_fixture);
  g_test_add("/MultiInterest/ClearIndicator/Scenario4",IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_test7, teardown_fixture);
  g_test_add("/MultiInterest/Properties/Scenario1", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_property_test1, teardown_fixture);
  g_test_add("/MultiInterest/Properties/Scenario2", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_property_test2, teardown_fixture);
  g_test_add("/MultiInterest/Properties/Scenario3", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_property_test3, teardown_fixture);
  g_test_add("/MultiInterest/Properties/Scenario4", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_multi_interest_property_test4, teardown_fixture);
  g_test_add("/Misc/Properties/InvalidReads", IndicatorModelTestFixture, NULL,
	     setup_fixture, test_invalid_property_reads, teardown_fixture);
  
  return g_test_run ();
}
