def setUp(self): def humedadRelativa(x): return HumedadRelativa(Porcentaje(x)) self.estadios = CicloDeVida.estadios() # argumentos para ensamblar los umbrales. Modificar a gusto. args = [[10, 30, 40, 50, 6.5, 7.5]] + [[12, 20, 40, 70, 6.0, 7.5]] * 7 x = [10, 30, 40, 50, 6.5, 7.5] # armamos los umbrales para cada estadio a partir de las # listas de argumentos self.umbrales = [] for i in range(len(self.estadios)): x = args[i] temperatura = Rango(TemperaturaEnCelsius(x[0]), TemperaturaEnCelsius(x[1])) humedad = Rango(humedadRelativa(x[2]), humedadRelativa(x[3])) acidez = Rango(AcidezEnPH(x[4]), AcidezEnPH(x[5])) self.umbrales.append( UmbralOptimoDeCultivo(self.estadios[i], temperatura, humedad, acidez)) # la lista de los nombres esperados para los estadios self.nombres = [ 'GERMINACION', 'DESARROLLO', 'BROTES', 'APARICION', 'FLORACION', 'FRUTO', 'MADURACION', 'SENESCENCIA' ]
def test_lapso_se_instancia_bien(self): desde = FechaYHora(date(2014, 9, 21), time(10, 45, 50)) hasta = FechaYHora(date(2014, 9, 22), time(10, 45, 50)) lapso = Rango(desde, hasta) self.assertEqual(desde, lapso.desde()) self.assertEqual(hasta, lapso.hasta())
def test_pronosticoMeteorologico_se_parsea(self): s = ("2014-09-27 11:00:0.0\n" "2014-09-27 11:59:59.0\n" "20\n" "55\n" "60\n" "1010\n" "2014-09-27 12:00:00.0\n" "2014-09-27 12:59:59.0\n" "25\n" "50\n" "65\n" "1020\n") result = ParserPronosticoMeteorologico().parse(s) prediccionesEsperadas = [ PrediccionMeteorologica( Rango(FechaYHora(date(2014, 9, 27), time(11, 0, 0)), FechaYHora(date(2014, 9, 27), time(11, 59, 59))), TemperaturaEnCelsius(20), Porcentaje(55), HumedadRelativa(Porcentaje(60)), LuzEnLux(1010)), PrediccionMeteorologica( Rango(FechaYHora(date(2014, 9, 27), time(12, 0, 0)), FechaYHora(date(2014, 9, 27), time(12, 59, 59))), TemperaturaEnCelsius(25), Porcentaje(50), HumedadRelativa(Porcentaje(65)), LuzEnLux(1020)), ] expected = PronosticoMeteorologico(prediccionesEsperadas) self.assertEqual(expected, result)
def test_lapso_contiene_fechaYHora_contenida_en_el_lapso(self): desde = FechaYHora(date(2014, 9, 21), time(10, 45, 50)) hasta = FechaYHora(date(2014, 9, 22), time(10, 45, 50)) lapso = Rango(desde, hasta) unaFechaYHora = FechaYHora(date(2014, 9, 21), time(12, 45, 50)) self.assertTrue(lapso.contiene(unaFechaYHora))
def test_dos_lapsos_iguales_son_iguales(self): desde1 = FechaYHora(date(2014, 9, 21), time(10, 45, 50)) hasta1 = FechaYHora(date(2014, 9, 22), time(10, 45, 50)) lapso1 = Rango(desde1, hasta1) desde2 = FechaYHora(date(2014, 9, 21), time(10, 45, 50)) hasta2 = FechaYHora(date(2014, 9, 22), time(10, 45, 50)) lapso2 = Rango(desde2, hasta2) self.assertTrue(lapso1 == lapso2)
def test_prediccion_se_construye_correctamente(self): desde = FechaYHora(date(2014, 9, 20), time(10, 45, 50)) hasta = FechaYHora(date(2014, 9, 20), time(13, 45, 50)) prediccion = PrediccionMeteorologica(Rango(desde, hasta), TemperaturaEnCelsius(25), Porcentaje(40), HumedadRelativa(Porcentaje(10)), LuzEnLux(800)) self.assertEqual(Rango(desde, hasta), prediccion.lapso()) self.assertEqual(TemperaturaEnCelsius(25), prediccion.temperatura()) self.assertEqual(Porcentaje(40), prediccion.probabilidadDeLluvia()) self.assertEqual(HumedadRelativa(Porcentaje(10)), prediccion.humedad()) self.assertEqual(LuzEnLux(800), prediccion.luzAmbiente())
def setUp(self): self.desdeLapso1 = FechaYHora(date(2014, 9, 21), time(10, 45, 50)) self.hastaLapso1 = FechaYHora(date(2014, 9, 21), time(13, 45, 50)) self.desdeLapso2 = FechaYHora(date(2014, 9, 20), time(10, 45, 50)) self.hastaLapso2 = FechaYHora(date(2014, 9, 20), time(13, 45, 50)) self.prediccion1 = PrediccionMeteorologica( Rango(self.desdeLapso1, self.hastaLapso1), TemperaturaEnCelsius(20), Porcentaje(80), HumedadRelativa(Porcentaje(50)), LuzEnLux(1000)) self.prediccion2 = PrediccionMeteorologica( Rango(self.desdeLapso2, self.hastaLapso2), TemperaturaEnCelsius(25), Porcentaje(40), HumedadRelativa(Porcentaje(10)), LuzEnLux(800))
def parse(self, unaCadena): # El formato es: # desdeLapso # hastaLapso # temp # lluvia # humedad # luz # desdeLapso # ... predicciones = [] datosSerializados = unaCadena.split("\n") for i in range(0, len(datosSerializados) - 1, 6): desde = CadenaAFechaYHora().parse(datosSerializados[i]) hasta = CadenaAFechaYHora().parse(datosSerializados[i + 1]) temp = TemperaturaEnCelsius(CadenaANumero().parse( datosSerializados[i + 2])) lluvia = CadenaAPorcentaje().parse(datosSerializados[i + 3]) humedad = HumedadRelativa(CadenaAPorcentaje().parse( datosSerializados[i + 4])) luz = LuzEnLux(CadenaANumero().parse(datosSerializados[i + 5])) predicciones.append( icherry.central_meteorologica.PrediccionMeteorologica( Rango(desde, hasta), temp, lluvia, humedad, luz)) return icherry.central_meteorologica.PronosticoMeteorologico( predicciones)
def generar(self): ahora = self._ahora() programa = ProgramaDeSuministro( Rango(ahora, ahora.agregarDuracion(DuracionEnHoras(24)))) # regar 100 mililitros una vez por hora for i in range(24): programa.programarAccion(self._shift(DuracionEnHoras(i), ahora), AccionRegado(LiquidoEnMililitros(100))) # poner la lámpara a 800 lux a las 5:15 y en 1000 lux a las 10:15 programa.programarAccion( self._shift(DuracionEnMinutos(60 * 5 + 15), ahora), AccionLuz(LuzEnLux(800))) programa.programarAccion( self._shift(DuracionEnMinutos(60 * 10 + 15), ahora), AccionLuz(LuzEnLux(1000))) # aplicar fertilizante a cada 4 horas for i in range(6): programa.programarAccion( self._shift(DuracionEnMinutos(60 * i * 4 + 25), ahora), AccionFertilizante(LiquidoEnMililitros(50))) # aplicar antibiótico a las 12 programa.programarAccion(self._shift(DuracionEnHoras(12), ahora), AccionAntibiotico(LiquidoEnMililitros(10))) self._programaDeSuministro.copiar(programa) self._programaDeSuministro.notificarObservers()
def test_rango_interseccion(self): # Este test está basado en la idea de un grafo de intervalos # (cada vértice representa un intervalo, dos vertices son # adyacentes si y sólo si los intervalos respectivos se # intersecan). # 0--1--2--3--4--5--6--7--8--9 # r1 |--------| # r2 |-----| # r3 |--------| # r4 |-----------------------| # r5 |--------| # # dibujito del grafo: # # r1------------r3 # | -\ /- | # | -\ /- | # | -\/ | # | r4-----r5 # | /-- # | /- # r2 # Armamos el grafo y verificamos todas las combinaciones # posibles de cada par de vértices. Esto hace un test # exhaustivo de todo el grafo (verifica tanto los pares # adyacentes como los no adyacentes). r1, r2, r3, r4, r5 = Rango(2, 5), Rango(1, 3), Rango(4, 7), Rango(0, 8), Rango(6, 9) vertices = {r1, r2, r3, r4, r5} r1.__ady = {r2, r3, r4} r2.__ady = {r1, r4} r3.__ady = {r1, r4, r5} r4.__ady = {r1, r2, r3, r5} r5.__ady = {r3, r4} for v in vertices: self.chk_eje(v, v) # reflexividad for w in v.__ady: # adyacencia dirigida self.chk_eje(v, w) for w in ((vertices - v.__ady) - {v}): # no-adyacencia dirigida self.chk_no_eje(v, w)
def test_acciones_removidas(self): # en este test verificamos que las acciones sean correctamente # removidas del programa de suministro. Vamos a usar cualquier # fruta como los datos del programa de suministro porque no # interesa ya demasiado el tema de las fechas y hora (eso ya # lo probamos antes). p = ProgramaDeSuministro(Rango(1, 10)) for i in range(1, 7): p.programarAccion(i, str(i)) # pequeño sanity check antes de empezar self.assertEqual(set(p.accionesEnHorario(p.lapso())), {'1', '2', '3', '4', '5', '6'}) def chk_remove(rango, accionesRemovidas, accionesRestantes): """verifica que dado un rango, el programa de suministro encuentre las acciones removidas, las remueva y finalmente se quede sólo con las acciones finales (ambos argumentos son conjuntos) """ self.assertEqual(set(p.retirarAccionesEnHorario(rango)), accionesRemovidas) self.assertEqual( set([aP.accion() for aP in p.accionesProgramadas()]), accionesRestantes) # removemos '3' y '4' chk_remove(Rango(3, 4), {'3', '4'}, {'1', '2', '5', '6'}) # removemos '6,' chk_remove(Rango(5.5, 100), {'6'}, {'1', '2', '5'}) # removemos '1' y '2,' chk_remove(Rango(-10, 2.8), {'1', '2'}, {'5'}) # removemos '5', queda vacío chk_remove(Rango(-10, 10), {'5'}, set())
def test_central_meteorologica_devuelve_pronostico(self): desde = FechaYHora(date(2014, 9, 21), time(10, 45, 50)) hasta = FechaYHora(date(2014, 9, 21), time(12, 45, 50)) predictor = PredictorMeteorologicoMock(TemperaturaEnCelsius(25), Porcentaje(40), HumedadRelativa(Porcentaje(10)), LuzEnLux(800)) central = CentralMeteorologica(predictor, None) self.assertIsNone(central.ultimoPronostico()) pronostico = central.obtenerPronostico(desdeFechaYHora=desde, cantidadDeHs=2) self.assertEqual(desde, pronostico.fechaInicio()) self.assertEqual(hasta, pronostico.fechaFin()) prediccion1 = pronostico.prediccionPara( FechaYHora(date(2014, 9, 21), time(11, 40, 50))) self.assertEqual( Rango(desde, desde.agregarDuracion(DuracionEnHoras(1))), prediccion1.lapso()) self.assertEqual(TemperaturaEnCelsius(25), prediccion1.temperatura()) self.assertEqual(Porcentaje(40), prediccion1.probabilidadDeLluvia()) self.assertEqual(HumedadRelativa(Porcentaje(10)), prediccion1.humedad()) self.assertEqual(LuzEnLux(800), prediccion1.luzAmbiente()) prediccion2 = pronostico.prediccionPara( FechaYHora(date(2014, 9, 21), time(12, 40, 50))) self.assertEqual( Rango(desde.agregarDuracion(DuracionEnHoras(1)), hasta), prediccion2.lapso()) self.assertEqual(TemperaturaEnCelsius(25), prediccion2.temperatura()) self.assertEqual(Porcentaje(40), prediccion2.probabilidadDeLluvia()) self.assertEqual(HumedadRelativa(Porcentaje(10)), prediccion2.humedad()) self.assertEqual(LuzEnLux(800), prediccion2.luzAmbiente())
def obtenerPronostico(self, desdeFechaYHora, cantidadDeHs): predicciones = [] desde = desdeFechaYHora for i in range(cantidadDeHs): hasta = desde.agregarHoras(1) predicciones.append( self.__predictorMeteorologico.prediccionPara( Rango(desde, hasta))) desde = desde.agregarHoras(1) self.__ultimoPronostico = PronosticoMeteorologico(predicciones) self.notificarObservers() return self.__ultimoPronostico
def planificarAcciones(self, fechaYHora): """Ejecuta todas las acciones del programa de suministro que recaigan en el lapso que comienza en la fechaYHora parámetro y dura tanto como se haya especificado en la duración de planificación (i.e. el lapso [f,f+δ] donde 'δ' es la duración y 'f' el parámetro fechaYHora). Todas estas acciones son retiradas del programa de suministro. """ desde = fechaYHora hasta = fechaYHora.agregarDuracion(self._duracionDePlanificacion) lapso = Rango(desde, hasta) accionesAEjecutar = self._programaDeSuministro.retirarAccionesEnHorario( lapso) for accion in accionesAEjecutar: self._ejecutor.ejecutarAccion(accion) self._programaDeSuministro.notificarObservers()
def test_rango_interseccion(self): # Este test está basado en la idea de un grafo de intervalos # (cada vértice representa un intervalo, dos vertices son # adyacentes si y sólo si los intervalos respectivos se # intersecan). # 0--1--2--3--4--5--6--7--8--9 # r1 |--------| # r2 |-----| # r3 |--------| # r4 |-----------------------| # r5 |--------| # # dibujito del grafo: # # r1------------r3 # | -\ /- | # | -\ /- | # | -\/ | # | r4-----r5 # | /-- # | /- # r2 # Armamos el grafo y verificamos todas las combinaciones # posibles de cada par de vértices. Esto hace un test # exhaustivo de todo el grafo (verifica tanto los pares # adyacentes como los no adyacentes). r1, r2, r3, r4, r5 = Rango(2, 5), Rango(1, 3), Rango(4, 7), Rango( 0, 8), Rango(6, 9) vertices = {r1, r2, r3, r4, r5} r1.__ady = {r2, r3, r4} r2.__ady = {r1, r4} r3.__ady = {r1, r4, r5} r4.__ady = {r1, r2, r3, r5} r5.__ady = {r3, r4} for v in vertices: self.chk_eje(v, v) # reflexividad for w in v.__ady: # adyacencia dirigida self.chk_eje(v, w) for w in ((vertices - v.__ady) - {v}): # no-adyacencia dirigida self.chk_no_eje(v, w)
def demo(): ahora = FechaYHora(date(1998, 7, 10), time(17, 0, 0)) # modificar a gusto! class CentralMeteorologicaMock: def __init__(self, fechaYHora=ahora): self.redefinirFechaYHora(fechaYHora) def redefinirFechaYHora(self, FechaYHora): self._ahora = FechaYHora def obtenerFechaYHora(self): return self._ahora def mostrar(gps, cm): print("==== Programa de Suministro ====") print("A partir de fecha/hora : %s" % cm.obtenerFechaYHora()) aps = programa.accionesProgramadas() for ap in aps: fh = ap.fechaYHora() print("%s : %s %s" % (fh.fecha(), fh.hora(), ap.accion().nombre())) print("%d acciones en total" % len(aps)) cm = CentralMeteorologicaMock() programa = ProgramaDeSuministro( Rango(ahora, ahora.agregarDuracion(DuracionEnHoras(24)))) gps = GeneradorDeProgramaDeSuministroFijo24(planMaestro=None, estadoDePlanta=None, centralMeteorologica=cm, programaDeSuministro=programa) gps.generar() mostrar(gps, cm) cm.redefinirFechaYHora( ahora.agregarDuracion(DuracionEnMinutos(60 * 10 + 15))) gps.generar() mostrar(gps, cm)
def lapso(desde, hasta): return Rango(diaN(desde), diaN(hasta))
# contando desde 0 return FechaYHora(_dia0 + timedelta(days=n), _hora) # una lista de pares para interpretar como lista de acciones. Lo único # que realmente interesa son los horarios (que en este caso son # instancias de fechaYHora, pero incluso podrían ser números (como fue # la primera versión de este test)), las 'acciones' las suplantamos # con cualquier banana (magia del mundo dinámico) porque no hacen nada # por ahora. _lista = [(diaN(0), 'primera'), (diaN(1), 'segunda'), (diaN(2), 'tercera'), (diaN(3), 'cuarta'), (diaN(4), 'quinta'), (diaN(5), 'sexta')] # el lapso en el que trabajamos (alcanza con que abarque a los # horarios de la lista, puede tener exceso). _lapso = Rango(diaN(-2), diaN(8)) class TestProgramaDeSuministro(unittest.TestCase): # def sortAccionesProgramadas(self, lista): # return sorted(lista) def accionesProgramadas2tuplas(self, lista): return [(aP.fechaYHora(), aP.accion()) for aP in lista] def chk_accionesProgramadas(self, programa, lista1): """verifica que la lista de acciones programadas, ordenadas por horario, es igual que la lista pasada como argumento. """ lista2 = [(aP.fechaYHora(), aP.accion())
def test_planificador_planifica_ejecucion_hora_por_hora(self): hora = FechaYHora(date(1998, 7, 10), time(17, 0, 0)) kit = KitEjecucion() # inicializamos un programa de suministro vacío programa = ProgramaDeSuministro( Rango(hora, hora.agregarDuracion(DuracionEnHoras(3)))) # programamos las acciones que entran en la primer hora programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(15)), AccionRegado(LiquidoEnMililitros(200))) programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(20)), AccionLuz(LuzEnLux(800))) programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(35)), AccionFertilizante(LiquidoEnMililitros(100))) programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(40)), AccionRegado(LiquidoEnMililitros(20))) programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(50)), AccionAntibiotico(LiquidoEnMililitros(10))) # programamos las acciones que entran en la segunda hora programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(75)), AccionRegado(LiquidoEnMililitros(100))) programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(90)), AccionLuz(LuzEnLux(500))) # programamos las acciones que entran en la tercer hora programa.programarAccion(hora.agregarDuracion(DuracionEnMinutos(130)), AccionAntibiotico(LiquidoEnMililitros(10))) # ok, está cargado el programa. Creamos entonces el # planificador, lo configuramos para que ejecute sobre el kit # con el programa dado a intervalos de una hora. Obviamente no # hay temporizadores acá así que vamos a llamarlo manualmente # por cada hora. planificador = PlanificadorDeEjecucion(DuracionEnHoras(1), programa, kit.ejecutor) # WARNING. los números están clavados. si se cambian arriba, # deben cambiarse acá abajo (sumando todo con cuidado). # ejecutamos la primer hora cuantasAntes = len(programa.accionesProgramadas()) planificador.planificarAcciones(hora) self.assertEqual(kit.fertilizante(), 100) self.assertEqual(kit.luz(), 800) self.assertEqual(kit.agua(), 220) self.assertEqual(kit.antibiotico(), 10) cuantasDespues = len(programa.accionesProgramadas()) self.assertEqual(cuantasAntes - cuantasDespues, 5) # ejecutamos la segunda hora cuantasAntes = len(programa.accionesProgramadas()) planificador.planificarAcciones( hora.agregarDuracion(DuracionEnHoras(1))) self.assertEqual(kit.fertilizante(), 100 + 0) self.assertEqual(kit.luz(), 800 + 500) self.assertEqual(kit.agua(), 220 + 100) self.assertEqual(kit.antibiotico(), 10 + 0) cuantasDespues = len(programa.accionesProgramadas()) self.assertEqual(cuantasAntes - cuantasDespues, 2) # ejecutamos la tercer hora cuantasAntes = len(programa.accionesProgramadas()) planificador.planificarAcciones( hora.agregarDuracion(DuracionEnHoras(2))) self.assertEqual(kit.fertilizante(), 100 + 0 + 0) self.assertEqual(kit.luz(), 800 + 500 + 0) self.assertEqual(kit.agua(), 220 + 100 + 0) self.assertEqual(kit.antibiotico(), 10 + 0 + 10) cuantasDespues = len(programa.accionesProgramadas()) self.assertEqual(cuantasAntes - cuantasDespues, 1) # verificamos que el programa esté vacío self.assertEqual(programa.accionesProgramadas(), [])