text: # -*- coding: utf-8 -*-
  """Tests del modulo pydatajson."""
  
  import os.path
  from collections import OrderedDict
  from pprint import pprint
  
  import nose
  import vcr
  from nose.tools import assert_true, assert_false, assert_equal, assert_list_equal, assert_raises
  from six import iteritems
  
  try:
      import mock
  except ImportError:
      from unittest import mock
  import filecmp
  from .context import pydatajson
  from .support.decorators import load_expected_result, RESULTS_DIR
  
  my_vcr = vcr.VCR(
      path_transformer=vcr.VCR.ensure_suffix('.yaml'),
      cassette_library_dir=os.path.join("tests", "cassetes"),
      record_mode='once')
  
  
  class TestDataJsonTestCase(object):
      SAMPLES_DIR = os.path.join("tests", "samples")
      RESULTS_DIR = RESULTS_DIR
      TEMP_DIR = os.path.join("tests", "temp")
  
      @classmethod
      def get_sample(cls, sample_filename):
          return os.path.join(cls.SAMPLES_DIR, sample_filename)
  
      @classmethod
      def setUp(cls):
          cls.dj = pydatajson.DataJson(cls.get_sample("full_data.json"))
          cls.catalog = pydatajson.readers.read_catalog(
              cls.get_sample("full_data.json"))
          cls.maxDiff = None
          cls.longMessage = True
  
      @classmethod
      def tearDown(cls):
          del (cls.dj)
  
      # TESTS DE catalog_report
      # Reporte esperado para "full_data.json", con harvest = 0
      LOCAL_URL = os.path.join(SAMPLES_DIR, "full_data.json")
      EXPECTED_REPORT = [
          OrderedDict([
              ('catalog_metadata_url', 'tests/samples/full_data.json'),
              ('catalog_federation_id',
               'modernizacion'), ('catalog_federation_org',
                                  None), ('catalog_title', 'Datos Argentina'),
              ('catalog_description',
               'Portal de Datos Abiertos del Gobierno de la Rep\xfablica Argentina'
               ), ('valid_catalog_metadata',
                   1), ('valid_dataset_metadata',
                        1), ('dataset_index',
                             0), ('harvest',
                                  1), ('dataset_identifier',
                                       '99db6631-d1c9-470b-a73e-c62daa32c777'),
              ('dataset_title', 'Sistema de contrataciones electr\xf3nicas'),
              ('dataset_accrualPeriodicity', 'R/P1Y'),
              ('dataset_description',
               'Datos correspondientes al Sistema de Contrataciones Electr\xf3nicas (Argentina Compra)'
               ),
              ('dataset_publisher_name',
               'Ministerio de Modernizaci\xf3n. Secretar\xeda de Modernizaci\xf3n Administrativa. Oficina Nacional de Contrataciones'
               ), ('dataset_superTheme',
                   'econ'), ('dataset_theme',
                             'contrataciones, compras, convocatorias'),
              ('dataset_landingPage',
               'http://datos.gob.ar/dataset/sistema-de-contrataciones-electronicas-argentina-compra'
               ), ('dataset_landingPage_generated',
                   'dataset/99db6631-d1c9-470b-a73e-c62daa32c777'),
              ('dataset_issued', '2016-04-14T19:48:05.433640-03:00'),
              ('dataset_modified',
               '2016-04-19T19:48:05.433640-03:00'), ('distributions_formats',
                                                     '{"CSV": 1}'),
              ('distributions_list',
               '"Convocatorias abiertas durante el a\xf1o 2015": http://186.33.211.253/dataset/99db6631-d1c9-470b-a73e-c62daa32c420/resource/4b7447cb-31ff-4352-96c3-589d212e1cc9/download/convocatorias-abiertas-anio-2015.csv'
               ), ('dataset_license',
                   'Open Data Commons Open Database License 1.0'),
              ('dataset_language',
               'spa'), ('dataset_spatial',
                        'ARG'), ('dataset_temporal',
                                 '2015-01-01/2015-12-31'), ('notas', '')
          ]),
          OrderedDict([
              ('catalog_metadata_url', 'tests/samples/full_data.json'),
              ('catalog_federation_id',
               'modernizacion'), ('catalog_federation_org',
                                  None), ('catalog_title', 'Datos Argentina'),
              ('catalog_description',
               'Portal de Datos Abiertos del Gobierno de la Rep\xfablica Argentina'
               ), ('valid_catalog_metadata',
                   1), ('valid_dataset_metadata',
                        1), ('dataset_index',
                             1), ('harvest',
                                  1), ('dataset_identifier',
                                       '99db6631-d1c9-470b-a73e-c62daa32c420'),
              ('dataset_title',
               'Sistema de contrataciones electr\xf3nicas (sin datos)'),
              ('dataset_accrualPeriodicity', 'R/P1Y'),
              ('dataset_description',
               'Datos correspondientes al Sistema de Contrataciones Electr\xf3nicas (Argentina Compra) (sin datos)'
               ),
              ('dataset_publisher_name',
               'Ministerio de Modernizaci\xf3n. Secretar\xeda de Modernizaci\xf3n Administrativa. Oficina Nacional de Contrataciones'
               ), ('dataset_superTheme',
                   'ECON'), ('dataset_theme',
                             'contrataciones, compras, convocatorias'),
              ('dataset_landingPage',
               'http://datos.gob.ar/dataset/sistema-de-contrataciones-electronicas-argentina-compra'
               ), ('dataset_landingPage_generated',
                   'dataset/99db6631-d1c9-470b-a73e-c62daa32c420'),
              ('dataset_issued', '2016-04-14T19:48:05.433640-03:00'),
              ('dataset_modified',
               '2016-04-19T19:48:05.433640-03:00'), ('distributions_formats',
                                                     '{"PDF": 1}'),
              ('distributions_list',
               '"Convocatorias abiertas durante el a\xf1o 2015": http://186.33.211.253/dataset/99db6631-d1c9-470b-a73e-c62daa32c420/resource/4b7447cb-31ff-4352-96c3-589d212e1cc9/download/convocatorias-abiertas-anio-2015.pdf'
               ), ('dataset_license',
                   'Open Data Commons Open Database License 1.0'),
              ('dataset_language', 'spa'), ('dataset_spatial', 'ARG'),
              ('dataset_temporal',
               '2015-01-01/2015-12-31'), ('notas',
                                          'No tiene distribuciones con datos.')
          ])
      ]
  
      def test_catalog_report_harvest_good(self):
          """catalog_report() marcará para cosecha los datasets con metadata
          válida si harvest='valid'."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          actual = self.dj.catalog_report(
              catalog, harvest='good', catalog_id="modernizacion")
  
          expected = list(self.EXPECTED_REPORT)
          expected[0]["harvest"] = 1
          expected[1]["harvest"] = 0
  
          # Compruebo explícitamente que el valor de 'harvest' sea el esperado
          assert_equal(actual[0]["harvest"], expected[0]["harvest"])
          assert_equal(actual[1]["harvest"], expected[1]["harvest"])
          # Compruebo que toda la lista sea la esperada
          assert_list_equal(actual, expected)
  
      def test_catalog_report_harvest_valid(self):
          """catalog_report() marcará para cosecha los datasets con metadata
          válida si harvest='valid'."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          actual = self.dj.catalog_report(
              catalog, harvest='valid', catalog_id="modernizacion")
  
          expected = list(self.EXPECTED_REPORT)
          expected[0]["harvest"] = 1
          expected[1]["harvest"] = 1
  
          # Compruebo explícitamente que el valor de 'harvest' sea el esperado
          assert_equal(actual[0]["harvest"], expected[0]["harvest"])
          # Compruebo que toda la lista sea la esperada
          print(actual)
          assert_list_equal(actual, expected)
  
      def test_catalog_report_harvest_none(self):
          """catalog_report() no marcará ningún dataset para cosecha si
          harvest='none'."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          actual = self.dj.catalog_report(
              catalog, harvest='none', catalog_id="modernizacion")
  
          expected = list(self.EXPECTED_REPORT)
          expected[0]["harvest"] = 0
          expected[1]["harvest"] = 0
  
          # Compruebo explícitamente que el valor de 'harvest' sea el esperado
          assert_equal(actual[0]["harvest"], expected[0]["harvest"])
          # Compruebo que toda la lista sea la esperada
          assert_list_equal(actual, expected)
  
      def test_catalog_report_harvest_all(self):
          """catalog_report() marcará todo dataset para cosecha si
          harvest='all'."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          actual = self.dj.catalog_report(
              catalog, harvest='all', catalog_id="modernizacion")
  
          expected = list(self.EXPECTED_REPORT)
          expected[0]["harvest"] = 1
          expected[1]["harvest"] = 1
  
          # Compruebo explícitamente que el valor de 'harvest' sea el esperado
          assert_equal(actual[0]["harvest"], expected[0]["harvest"])
          # Compruebo que toda la lista sea la esperada
          assert_list_equal(actual, expected)
  
      def test_catalog_report_harvest_report(self):
          """catalog_report() marcará para cosecha los datasets presentes en
          `report` si harvest='report'."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          # Compruebo que no se harvestee nada si el reporte no incluye el
          # dataset del catálogo
          report = [("data.json", "Un dataset que no es")]
          actual = self.dj.catalog_report(
              catalog,
              harvest='report',
              report=report,
              catalog_id="modernizacion")
  
          expected = list(self.EXPECTED_REPORT)
          expected[0]["harvest"] = 0
          expected[1]["harvest"] = 0
  
          # Compruebo explícitamente que el valor de 'harvest' sea el esperado
          assert_equal(actual[0]["harvest"], expected[0]["harvest"])
          # Compruebo que toda la lista sea la esperada
          assert_list_equal(actual, expected)
  
          # Compruebo que sí se harvestee si el reporte incluye el dataset del
          # catálogo
          report = [(os.path.join(self.SAMPLES_DIR, "full_data.json"),
                     "Sistema de contrataciones electrónicas")]
          actual = self.dj.catalog_report(
              catalog,
              harvest='report',
              report=report,
              catalog_id="modernizacion")
  
          expected = list(self.EXPECTED_REPORT)
          expected[0]["harvest"] = 1
  
          # Compruebo explícitamente que el valor de 'harvest' sea el esperado
          assert_equal(actual[0]["harvest"], expected[0]["harvest"])
          # Compruebo que toda la lista sea la esperada
          assert_list_equal(actual, expected)
  
      @nose.tools.raises(ValueError)
      def test_catalog_report_harvest_report_without_report_file(self):
          """Si harvest='report' y report='None', se levanta un ValueError."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
          self.dj.catalog_report(catalog, harvest='report')
  
      @nose.tools.raises(ValueError)
      def test_catalog_report_invalid_harvest_value(self):
          """Si harvest not in ["all", "none", "valid", "report"] se levanta un
          ValueError."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
          self.dj.catalog_report(catalog, harvest='harvest')
  
      def test_catalog_report_missing_datasets(self):
          """Si la clave "dataset" de un catalogo no esta presente, el reporte es
          una tabla vacía."""
          catalog = os.path.join(self.SAMPLES_DIR, "missing_dataset.json")
          assert_list_equal(self.dj.catalog_report(catalog), [])
  
      def test_generate_datasets_report(self):
          """generate_datasets_report() debe unir correctamente los resultados de
          catalog_report()"""
  
          return_value = [{"ckan": "in a box", "portal": "andino", "capo": "si"}]
          self.dj.catalog_report = mock.MagicMock(return_value=return_value)
  
          catalogs = ["catalogo A", "catalogo B", "catalogo C"]
          actual = self.dj.generate_datasets_report(catalogs)
  
          expected = []
          for catalog in catalogs:
              expected.extend(return_value)
  
          assert_equal(actual, expected)
  
      def test_generate_datasets_report_single_catalog(self):
          """Invocar generate_datasets_report con una str que sea la ruta a un
          catálogo, o con una lista que sólo contenga esa misma string dan el
          mismo resultado."""
          catalog_str = os.path.join(self.SAMPLES_DIR, "full_data.json")
          catalog_list = [catalog_str]
  
          report_str = self.dj.generate_datasets_report(catalog_str)
          report_list = self.dj.generate_datasets_report(catalog_list)
  
          assert_list_equal(report_str, report_list)
  
      @mock.patch('pydatajson.writers.write_table')
      def test_export_generate_datasets_report(self, write_table_mock):
          """Si se pasa una ruta en `export_path`, generate_datasets_report llama
          a writers.write_table."""
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          self.dj.generate_datasets_report(catalog, export_path="una ruta")
  
          pydatajson.writers.write_table.assert_called_once()
  
      def test_generate_harvester_config_freq_none(self):
          """generate_harvester_config() debe filtrar el resultado de
          generate_datasets_report() a únicamente los 3 campos requeridos, y
          conservar el accrualPeriodicity original."""
  
          datasets_report = [{
              "catalog_metadata_url": 1,
              "dataset_title": 1,
              "dataset_accrualPeriodicity": 1,
              "otra key": 1,
              "catalog_federation_org": "organizacion-en-ckan",
              "catalog_federation_id": "organismo",
              "harvest": 0
          }, {
              "catalog_metadata_url": 2,
              "dataset_title": 2,
              "dataset_accrualPeriodicity": 2,
              "otra key": 2,
              "catalog_federation_org": "organizacion-en-ckan",
              "catalog_federation_id": "organismo",
              "harvest": 1
          }, {
              "catalog_metadata_url": 3,
              "dataset_title": 3,
              "dataset_accrualPeriodicity": 3,
              "otra key": 3,
              "catalog_federation_org": "organizacion-en-ckan",
              "catalog_federation_id": "organismo",
              "harvest": 1
          }]
  
          expected_config = [{
              "catalog_metadata_url": 2,
              "dataset_title": 2,
              "dataset_accrualPeriodicity": 2,
              "dataset_owner_org": "organizacion-en-ckan",
              "job_name": "organismo",
          }, {
              "catalog_metadata_url": 3,
              "dataset_title": 3,
              "dataset_accrualPeriodicity": 3,
              "dataset_owner_org": "organizacion-en-ckan",
              "job_name": "organismo",
          }]
  
          self.dj.generate_datasets_report = mock.MagicMock(
              return_value=datasets_report)
  
          actual_config = self.dj.generate_harvester_config(
              catalogs="un catalogo", harvest='valid', frequency=None)
  
          assert_list_equal(actual_config, expected_config)
  
      def test_generate_harvester_config_no_freq(self):
          """generate_harvester_config() debe filtrar el resultado de
          generate_datasets_report() a únicamente los 3 campos requeridos, y
          usar "R/P1D" como accrualPeriodicity"""
  
          datasets_report = [{
              "catalog_metadata_url": 1,
              "dataset_title": 1,
              "dataset_accrualPeriodicity": 1,
              "catalog_federation_org": "organizacion-en-ckan",
              "catalog_federation_id": "organismo",
              "otra key": 1,
              "harvest": 0
          }, {
              "catalog_metadata_url": 2,
              "dataset_title": 2,
              "dataset_accrualPeriodicity": 2,
              "catalog_federation_org": "organizacion-en-ckan",
              "catalog_federation_id": "organismo",
              "otra key": 2,
              "harvest": 1
          }, {
              "catalog_metadata_url": 3,
              "dataset_title": 3,
              "dataset_accrualPeriodicity": 3,
              "catalog_federation_org": "organizacion-en-ckan",
              "catalog_federation_id": "organismo",
              "otra key": 3,
              "harvest": 1
          }]
  
          expected_config = [{
              "catalog_metadata_url": 2,
              "dataset_title": 2,
              "dataset_accrualPeriodicity": "R/P1D",
              "dataset_owner_org": "organizacion-en-ckan",
              "job_name": "organismo",
          }, {
              "catalog_metadata_url": 3,
              "dataset_title": 3,
              "dataset_accrualPeriodicity": "R/P1D",
              "dataset_owner_org": "organizacion-en-ckan",
              "job_name": "organismo",
          }]
  
          self.dj.generate_datasets_report = mock.MagicMock(
              return_value=datasets_report)
  
          actual_config = self.dj.generate_harvester_config(
              catalogs="un catalogo", harvest='valid')
  
          assert_list_equal(actual_config, expected_config)
  
      # TESTS DE GENERATE_HARVESTABLE_CATALOGS
  
      CATALOG = {
          "title":
          "Micro Catalogo",
          "dataset": [{
              "title": "Dataset Valido",
              "description": "Descripción valida",
              "distribution": []
          }, {
              "title": "Dataset Invalido"
          }]
      }
  
      @mock.patch('pydatajson.readers.read_catalog', return_value=CATALOG.copy())
      def test_generate_harvestable_catalogs_all(self, patched_read_catalog):
  
          catalogs = ["URL Catalogo A", "URL Catalogo B"]
  
          expected = [pydatajson.readers.read_catalog(c) for c in catalogs]
          actual = self.dj.generate_harvestable_catalogs(catalogs, harvest='all')
  
          assert_equal(actual, expected)
  
      @mock.patch('pydatajson.readers.read_catalog', return_value=CATALOG.copy())
      def test_generate_harvestable_catalogs_none(self, patched_read_catalog):
  
          catalogs = ["URL Catalogo A", "URL Catalogo B"]
  
          harvest_none = self.dj.generate_harvestable_catalogs(
              catalogs, harvest='none')
  
          for catalog in harvest_none:
              # Una lista vacía es "falsa"
              assert_false(catalog["dataset"])
  
      REPORT = [{
          "catalog_metadata_url": "URL Catalogo A",
          "dataset_title": "Dataset Valido",
          "dataset_accrualPeriodicity": "eventual",
          "harvest": 1
      }, {
          "catalog_metadata_url": "URL Catalogo A",
          "dataset_title": "Dataset Invalido",
          "dataset_accrualPeriodicity": "eventual",
          "harvest": 0
      }, {
          "catalog_metadata_url": "URL Catalogo B",
          "dataset_title": "Dataset Valido",
          "dataset_accrualPeriodicity": "eventual",
          "harvest": 1
      }, {
          "catalog_metadata_url": "URL Catalogo B",
          "dataset_title": "Dataset Invalido",
          "dataset_accrualPeriodicity": "eventual",
          "harvest": 0
      }]
  
      @mock.patch(
          'pydatajson.DataJson.generate_datasets_report', return_value=REPORT)
      @mock.patch('pydatajson.readers.read_catalog', return_value=CATALOG.copy())
      def test_generate_harvestable_catalogs_valid(self, mock_read_catalog,
                                                   mock_gen_dsets_report):
  
          catalogs = ["URL Catalogo A", "URL Catalogo B"]
  
          expected_catalog = {
              "title":
              "Micro Catalogo",
              "dataset": [{
                  "title": "Dataset Valido",
                  "description": "Descripción valida",
                  "distribution": []
              }]
          }
          expected = [expected_catalog, expected_catalog]
  
          actual = self.dj.generate_harvestable_catalogs(
              catalogs, harvest='valid')
  
          assert_list_equal(actual, expected)
  
      @mock.patch(
          'pydatajson.DataJson.generate_datasets_report', return_value=REPORT)
      @mock.patch('pydatajson.readers.read_catalog', return_value=CATALOG.copy())
      def test_generate_harvestable_catalogs_report(self, mock_read_catalog,
                                                    mock_gen_dsets_report):
  
          catalogs = ["URL Catalogo A", "URL Catalogo B"]
  
          expected_catalog = {
              "title":
              "Micro Catalogo",
              "dataset": [{
                  "title": "Dataset Valido",
                  "description": "Descripción valida",
                  "distribution": []
              }]
          }
          expected = [expected_catalog, expected_catalog]
  
          datasets_to_harvest = [("URL Catalogo A", "Dataset Valido"),
                                 ("URL Catalogo B", "Dataset Valido")]
  
          actual = self.dj.generate_harvestable_catalogs(
              catalogs, harvest='report', report=datasets_to_harvest)
  
          # `expected` es igual que en la prueba anterior.
          assert_list_equal(actual, expected)
  
      def test_generate_datasets_summary(self):
          """Genera informe conciso sobre datasets correctamente."""
          catalog = os.path.join(self.SAMPLES_DIR,
                                 "several_datasets_for_harvest.json")
          actual = self.dj.generate_datasets_summary(catalog)
          expected = [
              OrderedDict(
                  [('indice', 0), ('titulo',
                                   'Sistema de contrataciones electrónicas UNO'),
                   ('identificador', None), ('estado_metadatos', 'ERROR'),
                   ('cant_errores', 4), ('cant_distribuciones', 4)]),
              OrderedDict([('indice',
                            1), ('titulo',
                                 'Sistema de contrataciones electrónicas DOS'),
                           ('identificador', None), ('estado_metadatos', 'OK'),
                           ('cant_errores', 0), ('cant_distribuciones', 1)]),
              OrderedDict([('indice',
                            2), ('titulo',
                                 'Sistema de contrataciones electrónicas TRES'),
                           ('identificador', None), ('estado_metadatos', 'OK'),
                           ('cant_errores', 0), ('cant_distribuciones', 1)])
          ]
  
          assert_list_equal(actual, expected)
  
      @my_vcr.use_cassette()
      def test_generate_catalog_readme(self):
          """Genera README para presentar un catálogo."""
          catalog = os.path.join(self.SAMPLES_DIR,
                                 "several_datasets_for_harvest.json")
          actual_filename = os.path.join(self.TEMP_DIR, "catalog_readme.md")
  
          expected_filename = os.path.join(self.RESULTS_DIR, "catalog_readme.md")
  
          self.dj.generate_catalog_readme(catalog, export_path=actual_filename)
  
          comparison = filecmp.cmp(actual_filename, expected_filename)
          if comparison:
              os.remove(actual_filename)
          else:
              """
  {} se escribió correctamente, pero no es idéntico al esperado. Por favor,
  revíselo manualmente""".format(actual_filename)
  
          assert_true(comparison)
  
      @my_vcr.use_cassette()
      def test_generate_catalog_indicators(self):
          catalog = os.path.join(self.SAMPLES_DIR, "several_datasets.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
  
          # Resultados esperados haciendo cuentas manuales sobre el catálogo
          expected = {
              'datasets_cant': 3,
              'distribuciones_cant': 6,
              'datasets_meta_ok_cant': 2,
              'datasets_meta_error_cant': 1,
              'datasets_meta_ok_pct': round(100 * float(2) / 3, 2),
          }
  
          for k, v in list(expected.items()):
              assert_true(indicators[k], v)
  
      @my_vcr.use_cassette()
      def test_date_indicators(self):
          from datetime import datetime
          catalog = os.path.join(self.SAMPLES_DIR, "several_datasets.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
          dias_diff = (datetime.now() - datetime(2016, 4, 14)).days
  
          expected = {
              'catalogo_ultima_actualizacion_dias': dias_diff,
              'datasets_actualizados_cant': 1,
              'datasets_desactualizados_cant': 2,
              'datasets_actualizados_pct': 100 * round(float(1) / 3, 2),
              'datasets_frecuencia_cant': {
                  'R/P1W': 1,
                  'R/P1M': 1,
                  'eventual': 1
              },
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      @my_vcr.use_cassette()
      def test_format_indicators(self):
          catalog = os.path.join(self.SAMPLES_DIR, "several_datasets.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
  
          expected = {
              'distribuciones_formatos_cant': {
                  'CSV': 1,
                  'XLSX': 1,
                  'PDF': 1
              }
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      def test_field_indicators_on_min_catalog(self):
          catalog = os.path.join(self.SAMPLES_DIR, "minimum_data.json")
  
          # Se espera un único catálogo como resultado, índice 0
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
  
          expected = {
              'campos_recomendados_pct': 0.0,
              'campos_optativos_pct': 0.0,
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      def test_field_indicators_on_full_catalog(self):
          catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          # Se espera un único catálogo como resultado, índice 0
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
  
          expected = {
              'campos_recomendados_pct': 95.45,
              'campos_optativos_pct': 100
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      def test_federation_indicators_same_catalog(self):
          catalog = os.path.join(self.SAMPLES_DIR, "several_datasets.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog, catalog)[1]
  
          # Esperado: todos los datasets están federados
          expected = {
              'datasets_federados_cant': 3,
              'datasets_no_federados_cant': 0,
              'datasets_no_federados': [],
              'datasets_federados_pct': 100
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      def test_federation_indicators_no_datasets(self):
          catalog = os.path.join(self.SAMPLES_DIR, "several_datasets.json")
          central = os.path.join(self.SAMPLES_DIR, "catalogo_justicia.json")
          indicators = self.dj.generate_catalogs_indicators(catalog, central)[1]
  
          # Esperado: ningún dataset está federado
          expected = {
              'datasets_federados_cant':
              0,
              'datasets_no_federados_cant':
              3,
              'datasets_no_federados':
              [('Sistema de contrataciones electrónicas UNO',
                None), ('Sistema de contrataciones electrónicas DOS', None),
               ('Sistema de contrataciones electrónicas TRES', None)],
              'datasets_federados_pct':
              0
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      def test_federation_indicators_removed_datasets(self):
  
          # CASO 1
          # se buscan los datasets federados en el central que fueron eliminados
          # en el específico pero no se encuentran porque el publisher.name no
          # tiene publicado ningún otro dataset en el catálogo específico
          catalog = os.path.join(self.SAMPLES_DIR,
                                 "catalogo_justicia_removed.json")
          central = os.path.join(self.SAMPLES_DIR, "catalogo_justicia.json")
          indicators = self.dj.generate_catalogs_indicators(catalog, central)[1]
  
          # Esperado: no se encuentra el dataset removido, porque el
          # publisher.name no existe en ningún otro dataset
          expected = {
              "datasets_federados_eliminados_cant": 0,
              "datasets_federados_eliminados": []
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
          # CASO 2
          # se buscan los datasets federados en el central que fueron eliminados
          # en el específico y se encuentran porque el publisher.name tiene
          # publicado otro dataset en el catálogo específico
          catalog = os.path.join(self.SAMPLES_DIR,
                                 "catalogo_justicia_removed_publisher.json")
          indicators = self.dj.generate_catalogs_indicators(catalog, central)[1]
          # Esperado: no se encuentra el dataset removido, porque el
          # publisher.name no existe en ningún otro dataset
          expected = {
              "datasets_federados_eliminados_cant":
              1,
              "datasets_federados_eliminados":
              [('Base de datos legislativos Infoleg',
                "http://datos.jus.gob.ar/dataset/base-de-datos-legislativos-infoleg"
                )]
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v)
  
      @my_vcr.use_cassette()
      def test_network_indicators(self):
          one_catalog = os.path.join(self.SAMPLES_DIR, "several_datasets.json")
          other_catalog = os.path.join(self.SAMPLES_DIR, "full_data.json")
  
          indicators, network_indicators = self.dj.generate_catalogs_indicators(
              [one_catalog, other_catalog])
  
          # Esperado: suma de los indicadores individuales
          # No se testean los indicadores de actualización porque las fechas no
          # se mantienen actualizadas
          expected = {
              'catalogos_cant': 2,
              'datasets_cant': 5,
              'distribuciones_cant': 8,
              'datasets_meta_ok_cant': 4,
              'datasets_meta_error_cant': 1,
              'datasets_meta_ok_pct': 100 * float(4) / 5,
              'distribuciones_formatos_cant': {
                  'CSV': 2,
                  'XLSX': 1,
                  'PDF': 2
              },
              'campos_optativos_pct': 33.33,
              'campos_recomendados_pct': 50.72,
          }
  
          for k, v in list(expected.items()):
              assert_equal(network_indicators[k], v)
  
      @my_vcr.use_cassette()
      def test_indicators_invalid_periodicity(self):
          catalog = os.path.join(self.SAMPLES_DIR,
                                 "malformed_accrualperiodicity.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
  
          # Periodicidad inválida se considera automáticamente como
          # catálogo desactualizado
          expected = {
              'datasets_actualizados_cant': 0,
              'datasets_desactualizados_cant': 1,
              'datasets_actualizados_pct': 0
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v, k)
  
      @my_vcr.use_cassette()
      def test_indicators_missing_periodicity(self):
          catalog = os.path.join(self.SAMPLES_DIR, "missing_periodicity.json")
  
          # Dataset con periodicidad faltante no aporta valores para indicadores
          # de tipo 'datasets_(des)actualizados'
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
          expected = {
              'datasets_actualizados_cant': 0,
              'datasets_desactualizados_cant': 0,
              'datasets_actualizados_pct': 0
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v, k)
  
      @my_vcr.use_cassette()
      def test_indicators_missing_dataset(self):
          catalog = os.path.join(self.SAMPLES_DIR, "missing_dataset.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
  
          # Catálogo sin datasets no aporta indicadores significativos
          expected = {
              'datasets_cant': 0,
              'datasets_meta_ok_cant': 0,
              'datasets_meta_error_cant': 0,
              'datasets_actualizados_cant': 0,
              'datasets_desactualizados_cant': 0,
              'datasets_actualizados_pct': 0,
              'distribuciones_formatos_cant': {},
              'datasets_frecuencia_cant': {}
          }
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v, k)
  
      @my_vcr.use_cassette()
      def test_last_updated_indicator_missing_issued_field(self):
          from datetime import datetime
          catalog = os.path.join(self.SAMPLES_DIR, "minimum_data.json")
  
          indicators = self.dj.generate_catalogs_indicators(catalog)[0][0]
          dias_diff = (datetime.now() - datetime(2016, 4, 14)).days
  
          # Catálogo no tiene 'issued', pero su dataset sí -> uso el del dataset
          expected = {'catalogo_ultima_actualizacion_dias': dias_diff}
  
          for k, v in list(expected.items()):
              assert_equal(indicators[k], v, k)
  
      def test_dataset_is_updated(self):
          catalog = os.path.join(self.SAMPLES_DIR, "catalogo_justicia.json")
  
          # Datasset con periodicity mensual vencida
          dataset = "Base de datos legislativos Infoleg"
          assert_false(self.dj.dataset_is_updated(catalog, dataset))
  
          # Dataset con periodicity eventual, siempre True
          dataset = "Declaración Jurada Patrimonial Integral de carácter público"
          assert_true(self.dj.dataset_is_updated(catalog, dataset))
  
      def test_date_network_indicators_empty_catalog(self):
          catalog = os.path.join(self.SAMPLES_DIR, "invalid_catalog_empty.json")
          indics, network_indics = self.dj.generate_catalogs_indicators(
              [catalog, catalog])
  
          for k, v in list(network_indics.items()):
              assert_true(v is not None)
  
      def test_DataJson_constructor(self):
          for key, value in iteritems(self.catalog):
              assert_equal(self.dj[key], value)
  
      def test_datasets_property(self):
          """La propiedad datasets equivale a clave 'dataset' de un catalog."""
          assert_equal(self.dj.datasets, self.catalog["dataset"])
          assert_equal(self.dj.datasets, self.dj["dataset"])
  
      @load_expected_result()
      def test_datasets(self, expected_result):
          datasets = self.dj.get_datasets()
          pprint(datasets)
          assert_equal(expected_result, datasets)
  
          datasets = self.dj.datasets
          pprint(datasets)
          assert_equal(expected_result, datasets)
  
      def test_datasets_without_catalog(self):
          with assert_raises(KeyError):
              dj = pydatajson.DataJson()
              datasets = dj.get_datasets()
  
          with assert_raises(KeyError):
              dj = pydatajson.DataJson()
              datasets = dj.datasets
  
      def test_distributions_property(self):
          """La propiedad distributions equivale a clave 'distribution' de un catalog."""
          distributions = []
          for dataset in self.catalog["dataset"]:
              for distribution in dataset["distribution"]:
                  distribution["dataset_identifier"] = dataset["identifier"]
                  distributions.append(distribution)
          assert_equal(self.dj.distributions, distributions)
  
          distributions = []
          for dataset in self.dj["dataset"]:
              for distribution in dataset["distribution"]:
                  distribution["dataset_identifier"] = dataset["identifier"]
                  distributions.append(distribution)
          assert_equal(self.dj.distributions, distributions)
  
      @load_expected_result()
      def test_distributions(self, expected_result):
          distributions = self.dj.get_distributions()
          pprint(distributions)
          assert_equal(expected_result, distributions)
  
          distributions = self.dj.distributions
          pprint(distributions)
          assert_equal(expected_result, distributions)
  
      def test_distributions_without_catalog(self):
          with assert_raises(KeyError):
              dj = pydatajson.DataJson()
              distributions = dj.get_distributions()
  
          with assert_raises(KeyError):
              dj = pydatajson.DataJson()
              distributions = dj.distributions
  
      def test_fields_property(self):
          """La propiedad fields equivale a clave 'field' de un catalog."""
          fields = []
          for dataset in self.catalog["dataset"]:
              for distribution in dataset["distribution"]:
                  if "field" in distribution:
                      for field in distribution["field"]:
                          field["dataset_identifier"] = dataset["identifier"]
                          field["distribution_identifier"] = distribution[
                              "identifier"]
                          fields.append(field)
          assert_equal(self.dj.fields, fields)
  
          fields = []
          for dataset in self.dj["dataset"]:
              for distribution in dataset["distribution"]:
                  if "field" in distribution:
                      for field in distribution["field"]:
                          field["dataset_identifier"] = dataset["identifier"]
                          field["distribution_identifier"] = distribution[
                              "identifier"]
                          fields.append(field)
          assert_equal(self.dj.fields, fields)
  
      @load_expected_result()
      def test_fields(self, expected_result):
          fields = self.dj.get_fields()
          pprint(fields)
          assert_equal(expected_result, fields)
  
          fields = self.dj.fields
          pprint(fields)
          assert_equal(expected_result, fields)
  
      def test_fields_without_catalog(self):
          with assert_raises(KeyError):
              dj = pydatajson.DataJson()
              fields = dj.get_fields()
  
          with assert_raises(KeyError):
              dj = pydatajson.DataJson()
              fields = dj.fields
  
  
  if __name__ == '__main__':
      nose.run(defaultTest=__name__)
  