first commit
This commit is contained in:
commit
a233e18c0b
48 changed files with 55300 additions and 0 deletions
3
tests/__init__.py
Normal file
3
tests/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Test package for Atmo Data Wrapper
|
||||
"""
|
174
tests/test_credentials_system.py
Normal file
174
tests/test_credentials_system.py
Normal file
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test du système de credentials sans connexion réelle
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
def test_credentials_loading():
|
||||
"""Test du chargement des credentials"""
|
||||
print("=== Test du système de credentials ===\n")
|
||||
|
||||
# Test 1: Fichier manquant
|
||||
print("1. Test fichier credentials manquant...")
|
||||
client = AtmoDataClient(credentials_file="inexistant.json")
|
||||
|
||||
try:
|
||||
client._load_credentials()
|
||||
print("❌ Erreur: Exception attendue pour fichier manquant")
|
||||
except AtmoDataException as e:
|
||||
if "non trouvé" in str(e):
|
||||
print("✅ Exception correcte pour fichier manquant")
|
||||
else:
|
||||
print(f"❌ Message d'erreur inattendu: {e}")
|
||||
|
||||
# Test 2: Fichier JSON invalide
|
||||
print("\n2. Test fichier JSON invalide...")
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as f:
|
||||
f.write("{ invalid json }")
|
||||
invalid_file = f.name
|
||||
|
||||
try:
|
||||
client_invalid = AtmoDataClient(credentials_file=invalid_file)
|
||||
client_invalid._load_credentials()
|
||||
print("❌ Erreur: Exception attendue pour JSON invalide")
|
||||
except AtmoDataException as e:
|
||||
if "JSON" in str(e):
|
||||
print("✅ Exception correcte pour JSON invalide")
|
||||
else:
|
||||
print(f"❌ Message d'erreur inattendu: {e}")
|
||||
finally:
|
||||
os.unlink(invalid_file)
|
||||
|
||||
# Test 3: Champs manquants
|
||||
print("\n3. Test champs manquants...")
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as f:
|
||||
json.dump({"username": "test"}, f) # Manque password
|
||||
incomplete_file = f.name
|
||||
|
||||
try:
|
||||
client_incomplete = AtmoDataClient(credentials_file=incomplete_file)
|
||||
client_incomplete._load_credentials()
|
||||
print("❌ Erreur: Exception attendue pour champs manquants")
|
||||
except ValueError as e:
|
||||
if "manquants" in str(e):
|
||||
print("✅ Exception correcte pour champs manquants")
|
||||
else:
|
||||
print(f"❌ Message d'erreur inattendu: {e}")
|
||||
finally:
|
||||
os.unlink(incomplete_file)
|
||||
|
||||
# Test 4: Fichier valide
|
||||
print("\n4. Test fichier credentials valide...")
|
||||
test_credentials = {
|
||||
"username": "test_user",
|
||||
"password": "test_pass",
|
||||
"api_url": "https://test-api.example.com"
|
||||
}
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as f:
|
||||
json.dump(test_credentials, f)
|
||||
valid_file = f.name
|
||||
|
||||
try:
|
||||
client_valid = AtmoDataClient(credentials_file=valid_file)
|
||||
credentials = client_valid._load_credentials()
|
||||
|
||||
if credentials['username'] == 'test_user' and credentials['password'] == 'test_pass':
|
||||
print("✅ Credentials chargés correctement")
|
||||
print(f" Username: {credentials['username']}")
|
||||
print(f" API URL mise à jour: {client_valid.base_url}")
|
||||
else:
|
||||
print("❌ Credentials incorrects")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur inattendue: {e}")
|
||||
finally:
|
||||
os.unlink(valid_file)
|
||||
|
||||
# Test 5: Login avec credentials
|
||||
print("\n5. Test méthode login avec credentials...")
|
||||
|
||||
# Créer un client avec mock
|
||||
client_mock = AtmoDataClient(credentials_file=valid_file)
|
||||
|
||||
# Mock de la méthode _make_request pour simuler réponse login
|
||||
def mock_post(url, json=None):
|
||||
class MockResponse:
|
||||
def raise_for_status(self):
|
||||
pass
|
||||
def json(self):
|
||||
return {"token": "test_token_123"}
|
||||
return MockResponse()
|
||||
|
||||
# Remplacer temporairement
|
||||
original_post = client_mock.session.post
|
||||
client_mock.session.post = mock_post
|
||||
|
||||
# Créer un fichier credentials temporaire pour ce test
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as f:
|
||||
json.dump(test_credentials, f)
|
||||
temp_cred_file = f.name
|
||||
|
||||
try:
|
||||
client_mock.credentials_file = temp_cred_file
|
||||
success = client_mock.login() # Sans paramètres, doit utiliser le fichier
|
||||
|
||||
if success and client_mock.token == "test_token_123":
|
||||
print("✅ Login avec credentials automatique réussi")
|
||||
else:
|
||||
print("❌ Login avec credentials échoué")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur login: {e}")
|
||||
finally:
|
||||
client_mock.session.post = original_post
|
||||
os.unlink(temp_cred_file)
|
||||
|
||||
print("\n=== Tests du système de credentials terminés ===")
|
||||
|
||||
def test_auto_login():
|
||||
"""Test de la méthode auto_login"""
|
||||
print("\n=== Test auto_login ===\n")
|
||||
|
||||
test_credentials = {
|
||||
"username": "auto_user",
|
||||
"password": "auto_pass"
|
||||
}
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.json') as f:
|
||||
json.dump(test_credentials, f)
|
||||
cred_file = f.name
|
||||
|
||||
try:
|
||||
client = AtmoDataClient(credentials_file=cred_file)
|
||||
|
||||
# Mock de la session
|
||||
def mock_post(url, json=None):
|
||||
class MockResponse:
|
||||
def raise_for_status(self):
|
||||
pass
|
||||
def json(self):
|
||||
return {"token": "auto_token_456"}
|
||||
return MockResponse()
|
||||
|
||||
client.session.post = mock_post
|
||||
|
||||
success = client.auto_login()
|
||||
|
||||
if success and client.token == "auto_token_456":
|
||||
print("✅ auto_login() fonctionne correctement")
|
||||
else:
|
||||
print("❌ auto_login() a échoué")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur auto_login: {e}")
|
||||
finally:
|
||||
os.unlink(cred_file)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_credentials_loading()
|
||||
test_auto_login()
|
187
tests/test_real_connection.py
Normal file
187
tests/test_real_connection.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test de connexion réelle à l'API Atmo Data
|
||||
Nécessite un fichier credentials.json valide
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
|
||||
from datetime import datetime
|
||||
|
||||
def test_real_api_connection():
|
||||
"""Test de connexion et requêtes réelles à l'API"""
|
||||
print("=== Test de connexion réelle à l'API Atmo Data ===\n")
|
||||
|
||||
try:
|
||||
# Initialisation du client
|
||||
client = AtmoDataClient()
|
||||
print("Client initialisé")
|
||||
|
||||
# Test de connexion automatique
|
||||
print("Tentative de connexion avec credentials.json...")
|
||||
success = client.auto_login()
|
||||
|
||||
if not success:
|
||||
print("❌ Échec de l'authentification")
|
||||
return False
|
||||
|
||||
print("✅ Connexion réussie !")
|
||||
print(f"URL de l'API: {client.base_url}")
|
||||
|
||||
# Test 1: Récupération des indices ATMO
|
||||
print("\n=== Test 1: Indices ATMO ===")
|
||||
try:
|
||||
indices = client.get_indices_atmo(format="geojson")
|
||||
print(f"✅ Indices ATMO récupérés: {len(indices)} éléments")
|
||||
|
||||
# Afficher un échantillon
|
||||
if len(indices) > 0:
|
||||
first_item = indices[0]
|
||||
print(f" Premier élément - Zone: {first_item.lib_zone}")
|
||||
print(f" Qualité: {first_item.get_qualificatif()}")
|
||||
print(f" AASQA: {first_item.get_aasqa_name()}")
|
||||
|
||||
# Statistiques
|
||||
stats = indices.get_statistics()
|
||||
print(f" Statistiques: {stats}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur récupération indices: {e}")
|
||||
|
||||
# Test 2: Épisodes de pollution
|
||||
print("\n=== Test 2: Épisodes de pollution ===")
|
||||
try:
|
||||
episodes = client.get_episodes_3jours(format="geojson")
|
||||
print(f"✅ Épisodes récupérés: {len(episodes)} éléments")
|
||||
|
||||
if len(episodes) > 0:
|
||||
alerts_actives = [ep for ep in episodes if ep.is_alert_active()]
|
||||
print(f" Alertes actives: {len(alerts_actives)}")
|
||||
|
||||
for episode in alerts_actives[:3]: # Max 3 exemples
|
||||
print(f" - {episode.lib_zone}: {episode.get_alert_level()} ({episode.lib_pol})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur récupération épisodes: {e}")
|
||||
|
||||
# Test 3: Données d'émissions (région)
|
||||
print("\n=== Test 3: Données d'émissions ===")
|
||||
try:
|
||||
emissions = client.get_emissions(
|
||||
echelle="region",
|
||||
format="geojson"
|
||||
)
|
||||
print(f"✅ Données d'émissions récupérées: {len(emissions)} éléments")
|
||||
|
||||
if len(emissions) > 0:
|
||||
first_emission = emissions[0]
|
||||
print(f" Premier territoire: {first_emission.name}")
|
||||
total_em = first_emission.get_total_emissions()
|
||||
print(f" NOx: {total_em['NOx']:.1f} t/an")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur récupération émissions: {e}")
|
||||
|
||||
# Test 4: Indices pollen
|
||||
print("\n=== Test 4: Indices pollen ===")
|
||||
try:
|
||||
pollens = client.get_indices_pollens(format="geojson")
|
||||
print(f"✅ Indices pollen récupérés: {len(pollens)} éléments")
|
||||
|
||||
if len(pollens) > 0:
|
||||
alerts_pollen = [p for p in pollens if p.is_alert_active()]
|
||||
print(f" Alertes pollen actives: {len(alerts_pollen)}")
|
||||
|
||||
for pollen in alerts_pollen[:3]: # Max 3 exemples
|
||||
dangerous = pollen.get_dangerous_pollens()
|
||||
if dangerous:
|
||||
print(f" - Pollens à risque: {', '.join(dangerous)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur récupération pollens: {e}")
|
||||
|
||||
# Test 5: Filtrage géographique (Paris)
|
||||
print("\n=== Test 5: Filtrage géographique ===")
|
||||
try:
|
||||
# Bounding box de Paris
|
||||
bbox = "2.2 48.8 2.4 48.9"
|
||||
indices_paris = client.get_indices_atmo(
|
||||
bounding_box=bbox,
|
||||
format="geojson"
|
||||
)
|
||||
print(f"✅ Indices Paris récupérés: {len(indices_paris)} éléments")
|
||||
|
||||
# Filtrage par proximité
|
||||
if len(indices_paris) > 0:
|
||||
from atmo_data_wrapper import Coordinates
|
||||
paris_center = Coordinates(2.3522, 48.8566)
|
||||
nearby = indices_paris.filter_by_coordinates(paris_center, 10.0)
|
||||
print(f" Dans un rayon de 10km: {len(nearby)} éléments")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur filtrage géographique: {e}")
|
||||
|
||||
print("\n✅ Tests terminés avec succès !")
|
||||
return True
|
||||
|
||||
except AtmoDataException as e:
|
||||
print(f"❌ Erreur API: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur inattendue: {e}")
|
||||
return False
|
||||
|
||||
def test_credentials_file():
|
||||
"""Test de présence et validité du fichier credentials"""
|
||||
print("=== Vérification du fichier credentials ===\n")
|
||||
|
||||
import os
|
||||
import json
|
||||
|
||||
credentials_file = "credentials.json"
|
||||
example_file = "credentials.json.example"
|
||||
|
||||
# Vérifier la présence du fichier exemple
|
||||
if os.path.exists(example_file):
|
||||
print(f"✅ Fichier exemple trouvé: {example_file}")
|
||||
else:
|
||||
print(f"❌ Fichier exemple manquant: {example_file}")
|
||||
|
||||
# Vérifier la présence du fichier credentials
|
||||
if os.path.exists(credentials_file):
|
||||
print(f"✅ Fichier credentials trouvé: {credentials_file}")
|
||||
|
||||
try:
|
||||
with open(credentials_file, 'r') as f:
|
||||
creds = json.load(f)
|
||||
|
||||
required_fields = ['username', 'password']
|
||||
missing_fields = [field for field in required_fields if field not in creds]
|
||||
|
||||
if missing_fields:
|
||||
print(f"❌ Champs manquants: {missing_fields}")
|
||||
else:
|
||||
print("✅ Structure du fichier credentials valide")
|
||||
|
||||
# Masquer les credentials sensibles
|
||||
safe_creds = {k: "***" if k in ['password'] else v for k, v in creds.items()}
|
||||
print(f" Contenu: {safe_creds}")
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"❌ Erreur de format JSON: {e}")
|
||||
|
||||
else:
|
||||
print(f"❌ Fichier credentials manquant: {credentials_file}")
|
||||
print(f"💡 Créez le fichier à partir de {example_file}")
|
||||
print(" 1. Copiez credentials.json.example vers credentials.json")
|
||||
print(" 2. Remplacez les valeurs par vos vrais identifiants")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test du fichier credentials d'abord
|
||||
test_credentials_file()
|
||||
print()
|
||||
|
||||
# Puis test de connexion réelle si possible
|
||||
if input("Tester la connexion réelle à l'API ? (y/n): ").lower() == 'y':
|
||||
test_real_api_connection()
|
||||
else:
|
||||
print("Test de connexion ignoré.")
|
177
tests/test_save_functionality.py
Normal file
177
tests/test_save_functionality.py
Normal file
|
@ -0,0 +1,177 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests pour la fonctionnalité de sauvegarde
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient
|
||||
import os
|
||||
import json
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
def test_save_functionality():
|
||||
"""Test complet de la fonctionnalité de sauvegarde"""
|
||||
print("=== Tests de la fonctionnalité de sauvegarde ===\n")
|
||||
|
||||
client = AtmoDataClient()
|
||||
|
||||
# Données de test
|
||||
test_data = {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [2.3522, 48.8566]
|
||||
},
|
||||
"properties": {
|
||||
"nom": "Test Paris",
|
||||
"valeur": 42.5,
|
||||
"date": "2024-07-07"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
test_dir = "test_files"
|
||||
|
||||
# Test 1: Validation du format
|
||||
print("1. Test de validation du format...")
|
||||
try:
|
||||
client._validate_save_format("json")
|
||||
print("✅ Format JSON valide")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur format JSON: {e}")
|
||||
|
||||
try:
|
||||
client._validate_save_format("xml")
|
||||
print("❌ Format XML invalide accepté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Format XML correctement rejeté: {e}")
|
||||
|
||||
# Test 2: Sauvegarde JSON
|
||||
print("\n2. Test sauvegarde JSON...")
|
||||
try:
|
||||
json_file = client.save_to_file(test_data, f"{test_dir}/test", "json")
|
||||
if os.path.exists(json_file):
|
||||
# Vérifier que le fichier est du JSON valide
|
||||
with open(json_file, 'r') as f:
|
||||
loaded_data = json.load(f)
|
||||
print("✅ Fichier JSON créé et valide")
|
||||
else:
|
||||
print("❌ Fichier JSON non créé")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur JSON: {e}")
|
||||
|
||||
# Test 3: Sauvegarde CSV
|
||||
print("\n3. Test sauvegarde CSV...")
|
||||
try:
|
||||
csv_file = client.save_to_file(test_data, f"{test_dir}/test", "csv")
|
||||
if os.path.exists(csv_file):
|
||||
# Vérifier le contenu CSV
|
||||
with open(csv_file, 'r') as f:
|
||||
reader = csv.reader(f)
|
||||
rows = list(reader)
|
||||
if len(rows) >= 2: # Header + au moins une ligne
|
||||
print("✅ Fichier CSV créé avec en-tête et données")
|
||||
else:
|
||||
print("❌ Fichier CSV incomplet")
|
||||
else:
|
||||
print("❌ Fichier CSV non créé")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur CSV: {e}")
|
||||
|
||||
# Test 4: Sauvegarde GeoJSON
|
||||
print("\n4. Test sauvegarde GeoJSON...")
|
||||
try:
|
||||
geojson_file = client.save_to_file(test_data, f"{test_dir}/test", "geojson")
|
||||
if os.path.exists(geojson_file):
|
||||
# Vérifier que c'est du GeoJSON valide
|
||||
with open(geojson_file, 'r') as f:
|
||||
loaded_data = json.load(f)
|
||||
if loaded_data.get('type') == 'FeatureCollection':
|
||||
print("✅ Fichier GeoJSON créé et valide")
|
||||
else:
|
||||
print("❌ Fichier GeoJSON invalide")
|
||||
else:
|
||||
print("❌ Fichier GeoJSON non créé")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur GeoJSON: {e}")
|
||||
|
||||
# Test 5: Création de répertoires
|
||||
print("\n5. Test création de répertoires...")
|
||||
try:
|
||||
nested_file = client.save_to_file(test_data, f"{test_dir}/nested/deep/test", "json")
|
||||
if os.path.exists(nested_file):
|
||||
print("✅ Répertoires imbriqués créés automatiquement")
|
||||
else:
|
||||
print("❌ Répertoires imbriqués non créés")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur création répertoires: {e}")
|
||||
|
||||
# Test 6: Extension automatique
|
||||
print("\n6. Test ajout automatique d'extension...")
|
||||
try:
|
||||
auto_ext_file = client.save_to_file(test_data, f"{test_dir}/sans_extension", "json")
|
||||
if auto_ext_file.endswith('.json'):
|
||||
print("✅ Extension .json ajoutée automatiquement")
|
||||
else:
|
||||
print("❌ Extension non ajoutée")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur extension automatique: {e}")
|
||||
|
||||
# Test 7: Données sans géométrie
|
||||
print("\n7. Test données sans géométrie...")
|
||||
data_no_geom = {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": None,
|
||||
"properties": {
|
||||
"nom": "Test sans géométrie",
|
||||
"valeur": 123
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
try:
|
||||
no_geom_file = client.save_to_file(data_no_geom, f"{test_dir}/no_geom", "csv")
|
||||
if os.path.exists(no_geom_file):
|
||||
with open(no_geom_file, 'r') as f:
|
||||
content = f.read()
|
||||
if 'nom,valeur' in content and 'Test sans géométrie,123' in content:
|
||||
print("✅ CSV sans géométrie créé correctement")
|
||||
else:
|
||||
print("❌ CSV sans géométrie incorrect")
|
||||
else:
|
||||
print("❌ Fichier sans géométrie non créé")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur données sans géométrie: {e}")
|
||||
|
||||
# Test 8: Données invalides pour GeoJSON
|
||||
print("\n8. Test données invalides pour GeoJSON...")
|
||||
invalid_geojson = {"data": "not a geojson"}
|
||||
|
||||
try:
|
||||
client.save_to_file(invalid_geojson, f"{test_dir}/invalid", "geojson")
|
||||
print("❌ Données invalides acceptées pour GeoJSON")
|
||||
except ValueError as e:
|
||||
print(f"✅ Données invalides correctement rejetées: {e}")
|
||||
|
||||
# Nettoyage
|
||||
print("\n9. Nettoyage des fichiers de test...")
|
||||
try:
|
||||
import shutil
|
||||
if os.path.exists(test_dir):
|
||||
shutil.rmtree(test_dir)
|
||||
print("✅ Fichiers de test supprimés")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur nettoyage: {e}")
|
||||
|
||||
print("\n=== Tests terminés ===")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_save_functionality()
|
107
tests/test_typed_client.py
Normal file
107
tests/test_typed_client.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test simple du client avec les nouveaux objets typés
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient
|
||||
from atmo_data_wrapper import AtmoDataCollection, IndiceAtmo
|
||||
|
||||
def test_client_integration():
|
||||
"""Test que le client retourne bien les bons types d'objets"""
|
||||
print("=== Test d'intégration client/modèles ===\n")
|
||||
|
||||
client = AtmoDataClient()
|
||||
|
||||
# Test avec données simulées (sans vraie connexion API)
|
||||
|
||||
# Simuler _make_request pour retourner des données de test
|
||||
def mock_make_request(endpoint, params=None):
|
||||
return {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [2.3522, 48.8566]
|
||||
},
|
||||
"properties": {
|
||||
"aasqa": "11",
|
||||
"code_qual": 3,
|
||||
"lib_qual": "Dégradé",
|
||||
"lib_zone": "Test Zone"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Remplacer temporairement la méthode
|
||||
original_make_request = client._make_request
|
||||
client._make_request = mock_make_request
|
||||
client.token = "test_token" # Simuler une connexion
|
||||
|
||||
try:
|
||||
# Test 1: get_indices_atmo avec format geojson -> AtmoDataCollection
|
||||
print("1. Test get_indices_atmo format geojson...")
|
||||
result = client.get_indices_atmo(format="geojson")
|
||||
|
||||
if isinstance(result, AtmoDataCollection):
|
||||
print("✅ Retourne bien AtmoDataCollection")
|
||||
print(f" Type de données: {result.data_type}")
|
||||
print(f" Nombre d'éléments: {len(result)}")
|
||||
|
||||
# Vérifier que les éléments sont du bon type
|
||||
if len(result) > 0 and isinstance(result[0], IndiceAtmo):
|
||||
print("✅ Les éléments sont bien des objets IndiceAtmo")
|
||||
print(f" Zone: {result[0].lib_zone}")
|
||||
print(f" Qualité: {result[0].get_qualificatif()}")
|
||||
else:
|
||||
print("❌ Les éléments ne sont pas des objets IndiceAtmo")
|
||||
else:
|
||||
print(f"❌ Retourne {type(result)} au lieu de AtmoDataCollection")
|
||||
|
||||
print()
|
||||
|
||||
# Test 2: Simuler format CSV -> dict
|
||||
def mock_csv_request(endpoint, params=None):
|
||||
return {"data": "csv,data,here"}
|
||||
|
||||
client._make_request = mock_csv_request
|
||||
|
||||
print("2. Test get_indices_atmo format csv...")
|
||||
result_csv = client.get_indices_atmo(format="csv")
|
||||
|
||||
if isinstance(result_csv, dict):
|
||||
print("✅ Format CSV retourne bien un dict")
|
||||
else:
|
||||
print(f"❌ Format CSV retourne {type(result_csv)} au lieu de dict")
|
||||
|
||||
print()
|
||||
|
||||
# Test 3: Test différents endpoints
|
||||
client._make_request = mock_make_request
|
||||
|
||||
endpoints_to_test = [
|
||||
("get_episodes_3jours", "episodes"),
|
||||
("get_emissions", "emissions"),
|
||||
("get_indices_pollens", "pollens")
|
||||
]
|
||||
|
||||
print("3. Test autres endpoints...")
|
||||
for method_name, expected_type in endpoints_to_test:
|
||||
method = getattr(client, method_name)
|
||||
result = method(format="geojson")
|
||||
|
||||
if isinstance(result, AtmoDataCollection) and result.data_type == expected_type:
|
||||
print(f"✅ {method_name} retourne bien AtmoDataCollection({expected_type})")
|
||||
else:
|
||||
print(f"❌ {method_name} problème de type: {type(result)}, data_type: {getattr(result, 'data_type', 'N/A')}")
|
||||
|
||||
print("\n=== Test terminé ===")
|
||||
|
||||
finally:
|
||||
# Restaurer la méthode originale
|
||||
client._make_request = original_make_request
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_client_integration()
|
261
tests/test_validations.py
Normal file
261
tests/test_validations.py
Normal file
|
@ -0,0 +1,261 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script de test pour valider les validations du wrapper AtmoDataClient
|
||||
"""
|
||||
|
||||
from atmo_data_wrapper import AtmoDataClient
|
||||
|
||||
def test_validations():
|
||||
"""Test des validations des paramètres"""
|
||||
client = AtmoDataClient()
|
||||
|
||||
print("=== Test des validations ===\n")
|
||||
|
||||
# Test format invalide
|
||||
try:
|
||||
client._validate_format("xml")
|
||||
print("❌ Format invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Format invalide détecté: {e}")
|
||||
|
||||
# Test format valide
|
||||
try:
|
||||
client._validate_format("geojson")
|
||||
print("✅ Format valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Format valide rejeté: {e}")
|
||||
|
||||
# Test AASQA invalide
|
||||
try:
|
||||
client._validate_aasqa("99")
|
||||
print("❌ Code AASQA invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Code AASQA invalide détecté: {e}")
|
||||
|
||||
# Test AASQA valide
|
||||
try:
|
||||
client._validate_aasqa("11")
|
||||
print("✅ Code AASQA valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Code AASQA valide rejeté: {e}")
|
||||
|
||||
# Test polluant invalide
|
||||
try:
|
||||
client._validate_polluant("CO")
|
||||
print("❌ Polluant invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Polluant invalide détecté: {e}")
|
||||
|
||||
# Test polluant valide
|
||||
try:
|
||||
client._validate_polluant("PM10")
|
||||
print("✅ Polluant valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Polluant valide rejeté: {e}")
|
||||
|
||||
# Test date invalide (format)
|
||||
try:
|
||||
client._validate_date("2024/06/08")
|
||||
print("❌ Format de date invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Format de date invalide détecté: {e}")
|
||||
|
||||
# Test date invalide (date inexistante)
|
||||
try:
|
||||
client._validate_date("2024-02-30")
|
||||
print("❌ Date inexistante non détectée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Date inexistante détectée: {e}")
|
||||
|
||||
# Test date valide
|
||||
try:
|
||||
client._validate_date("2024-06-08")
|
||||
print("✅ Date valide acceptée")
|
||||
except ValueError as e:
|
||||
print(f"❌ Date valide rejetée: {e}")
|
||||
|
||||
# Test code qualificatif ATMO invalide
|
||||
try:
|
||||
client._validate_code_qualificatif_atmo("8")
|
||||
print("❌ Code qualificatif ATMO invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Code qualificatif ATMO invalide détecté: {e}")
|
||||
|
||||
# Test code qualificatif ATMO valide
|
||||
try:
|
||||
client._validate_code_qualificatif_atmo("3")
|
||||
print("✅ Code qualificatif ATMO valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Code qualificatif ATMO valide rejeté: {e}")
|
||||
|
||||
# Test code qualificatif pollen invalide
|
||||
try:
|
||||
client._validate_code_qualificatif_pollen("7")
|
||||
print("❌ Code qualificatif pollen invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Code qualificatif pollen invalide détecté: {e}")
|
||||
|
||||
# Test code qualificatif pollen valide
|
||||
try:
|
||||
client._validate_code_qualificatif_pollen("4")
|
||||
print("✅ Code qualificatif pollen valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Code qualificatif pollen valide rejeté: {e}")
|
||||
|
||||
# Test type épisode invalide
|
||||
try:
|
||||
client._validate_type_episode("CRITIQUE")
|
||||
print("❌ Type épisode invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Type épisode invalide détecté: {e}")
|
||||
|
||||
# Test type épisode valide
|
||||
try:
|
||||
client._validate_type_episode("ALERTE")
|
||||
print("✅ Type épisode valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Type épisode valide rejeté: {e}")
|
||||
|
||||
# Test échéance invalide
|
||||
try:
|
||||
client._validate_echeance("2")
|
||||
print("❌ Échéance invalide non détectée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Échéance invalide détectée: {e}")
|
||||
|
||||
# Test échéance valide
|
||||
try:
|
||||
client._validate_echeance("-1")
|
||||
print("✅ Échéance valide acceptée")
|
||||
except ValueError as e:
|
||||
print(f"❌ Échéance valide rejetée: {e}")
|
||||
|
||||
# Test échelle invalide
|
||||
try:
|
||||
client._validate_echelle("commune")
|
||||
print("❌ Échelle invalide non détectée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Échelle invalide détectée: {e}")
|
||||
|
||||
# Test échelle valide
|
||||
try:
|
||||
client._validate_echelle("epci")
|
||||
print("✅ Échelle valide acceptée")
|
||||
except ValueError as e:
|
||||
print(f"❌ Échelle valide rejetée: {e}")
|
||||
|
||||
# Test secteur invalide
|
||||
try:
|
||||
client._validate_secteur("99")
|
||||
print("❌ Secteur invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Secteur invalide détecté: {e}")
|
||||
|
||||
# Test secteur valide
|
||||
try:
|
||||
client._validate_secteur("5")
|
||||
print("✅ Secteur valide accepté")
|
||||
except ValueError as e:
|
||||
print(f"❌ Secteur valide rejeté: {e}")
|
||||
|
||||
# Test bounding box invalide (format)
|
||||
try:
|
||||
client._validate_bounding_box("2.2 48.8 2.4")
|
||||
print("❌ Format bounding box invalide non détecté")
|
||||
except ValueError as e:
|
||||
print(f"✅ Format bounding box invalide détecté: {e}")
|
||||
|
||||
# Test bounding box invalide (coordonnées)
|
||||
try:
|
||||
client._validate_bounding_box("2.4 48.8 2.2 48.9")
|
||||
print("❌ Coordonnées bounding box invalides non détectées")
|
||||
except ValueError as e:
|
||||
print(f"✅ Coordonnées bounding box invalides détectées: {e}")
|
||||
|
||||
# Test bounding box valide
|
||||
try:
|
||||
client._validate_bounding_box("2.2 48.8 2.4 48.9")
|
||||
print("✅ Bounding box valide acceptée")
|
||||
except ValueError as e:
|
||||
print(f"❌ Bounding box valide rejetée: {e}")
|
||||
|
||||
print("\n=== Test des méthodes avec validations ===\n")
|
||||
|
||||
# Test méthode avec paramètres invalides
|
||||
try:
|
||||
client.get_indices_atmo(format="xml")
|
||||
print("❌ Méthode avec format invalide non bloquée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Méthode avec format invalide bloquée: {e}")
|
||||
|
||||
try:
|
||||
client.get_episodes_3jours(aasqa="99")
|
||||
print("❌ Méthode avec AASQA invalide non bloquée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Méthode avec AASQA invalide bloquée: {e}")
|
||||
|
||||
try:
|
||||
client.get_episodes_historique(date="2024/06/08")
|
||||
print("❌ Méthode avec date invalide non bloquée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Méthode avec date invalide bloquée: {e}")
|
||||
|
||||
try:
|
||||
client.get_emissions(echelle="commune")
|
||||
print("❌ Méthode avec échelle invalide non bloquée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Méthode avec échelle invalide bloquée: {e}")
|
||||
|
||||
try:
|
||||
client.get_indices_pollens(code_qualificatif="7")
|
||||
print("❌ Méthode avec code qualificatif pollen invalide non bloquée")
|
||||
except ValueError as e:
|
||||
print(f"✅ Méthode avec code qualificatif pollen invalide bloquée: {e}")
|
||||
|
||||
print("\n=== Tests terminés ===")
|
||||
|
||||
|
||||
def test_integration_examples():
|
||||
"""Test d'intégration avec des exemples réalistes"""
|
||||
print("\n=== Test d'intégration ===\n")
|
||||
|
||||
client = AtmoDataClient()
|
||||
|
||||
# Test avec paramètres valides (sans authentification)
|
||||
try:
|
||||
# Ces appels échoueront sur l'authentification mais les validations passeront
|
||||
client.get_indices_atmo(
|
||||
format="geojson",
|
||||
date="2024-06-08",
|
||||
aasqa="11",
|
||||
code_qualificatif="3"
|
||||
)
|
||||
print("❌ Appel réussi sans authentification")
|
||||
except ValueError as e:
|
||||
print(f"❌ Validation échouée avec paramètres valides: {e}")
|
||||
except Exception as e:
|
||||
if "Token non disponible" in str(e):
|
||||
print("✅ Validations réussies, échec sur l'authentification comme attendu")
|
||||
else:
|
||||
print(f"❌ Erreur inattendue: {e}")
|
||||
|
||||
try:
|
||||
client.get_episodes_3jours(
|
||||
format="csv",
|
||||
polluant="PM10",
|
||||
type_episode="ALERTE",
|
||||
echeance="0"
|
||||
)
|
||||
print("❌ Appel réussi sans authentification")
|
||||
except ValueError as e:
|
||||
print(f"❌ Validation échouée avec paramètres valides: {e}")
|
||||
except Exception as e:
|
||||
if "Token non disponible" in str(e):
|
||||
print("✅ Validations réussies, échec sur l'authentification comme attendu")
|
||||
else:
|
||||
print(f"❌ Erreur inattendue: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_validations()
|
||||
test_integration_examples()
|
Loading…
Add table
Add a link
Reference in a new issue