"""Jeito de gente do modo vida: reencontro e saudade, bom dia lembrando de ontem, pedidos com motivo, largar atividade no meio, personalidade e o console com o porquê de cada decisão.""" import random import sys import tempfile import time import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from console import Console # noqa: E402 from vida import Vida # noqa: E402 DIA = time.mktime((2026, 10, 12, 9, 0, 0, 0, 0, -1)) # uma segunda, 9h class HumanoTest(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.v = Vida(Path(self.tmp.name) / 'vida.json', iniciar=False, rng=random.Random(1)) self.ordens, self.linhas = [], [] self.v.enfileirar = self.ordens.append self.v.console = lambda origem, texto, motivo='', nivel='info', agora=None: self.linhas.append((origem, texto, motivo, nivel)) self.v.celular_online = lambda: True self.v.celular_dormindo = lambda: False self.v.madrugada = lambda agora: False self.perto = False self.v.alguem_perto = lambda: self.perto def tearDown(self): self.tmp.cleanup() def falas(self): return [o[6:] for o in self.ordens if o.startswith('dizer ')] def chegar(self, agora, ausencia): self.v.ultimo_perto = agora - ausencia self.v.perto_antes = False self.perto = True self.v.tick(agora) def test_reencontro_cresce_com_o_tempo_fora(self): self.v.saudou_dia = '2026-10-12' # bom dia já foi dado self.chegar(DIA, 5 * 60) # 5 min fora: nada self.assertEqual(self.falas(), []) self.assertNotIn('acenar', self.ordens) self.chegar(DIA + 100, 20 * 60) # 20 min: acena self.assertIn('acenar', self.ordens) self.chegar(DIA + 200, 2 * 3600) # 2 h: comemora self.assertEqual(self.falas()[-1], 'Oi! Você voltou!') social = self.v.necessidades['social'] self.chegar(DIA + 300, 6 * 3600) # 6 h: saudade self.assertEqual(self.falas()[-1], 'Senti sua falta!') self.assertIn('coracao', self.ordens) self.assertGreater(self.v.necessidades['social'], social) self.assertTrue(any('ninguém por perto havia 6h00' in m for _, _, m, _ in self.linhas)) def test_bom_dia_lembra_de_ontem(self): ontem = dict(presenca=[None] * 24, respostas=0, atos=8) ontem['presenca'][1] = 0.6 # ficaram acordados até as 2h self.v.dia_anterior = lambda: ontem self.v.acaso = random.Random(0) self.chegar(DIA, 8 * 3600) fala = self.falas()[0] self.assertTrue(fala.startswith('Bom dia! '), fala) self.assertIn(fala[9:], ['Ontem a gente ficou acordado até as 2h, hein!', 'Ontem ninguém brincou comigo... hoje vai ser diferente?']) self.assertEqual(self.v.saudou_dia, '2026-10-12') self.chegar(DIA + 3600, 30 * 60) # mesmo dia: não repete o bom dia self.assertEqual(len([f for f in self.falas() if f.startswith('Bom dia')]), 1) # de madrugada não faz festa self.v.madrugada = lambda agora: True n = len(self.falas()) self.chegar(DIA + 7200, 6 * 3600) self.assertEqual(len(self.falas()), n) def test_pede_o_que_falta_com_motivo_e_intervalo(self): self.v.saudou_dia = '2026-10-12' self.perto, self.v.perto_antes, self.v.visto_em = True, True, DIA self.v.atividade_em = DIA # sem folga para atividades self.v.necessidades.update(social=30, diversao=80, energia=80, alegria=70) self.v.acaso = random.Random(3) pedido = None for i in range(40): if self.v.agir(DIA + i) == 'pedido': pedido = DIA + i break self.assertIsNotNone(pedido) self.assertEqual(self.falas()[-1], 'Tô carente... me faz um carinho?') self.assertIn('social 30', self.v.porque) self.assertEqual(self.v.diario[0]['tipo'], 'pedido') n = len(self.falas()) for i in range(40): # menos de 20 min depois: não pede de novo self.v.agir(pedido + 60 + i) self.assertEqual(len(self.falas()), n) def test_larga_atividade_no_meio_e_conta(self): self.v.acaso = random.Random(0) largou = None for i in range(60): self.v.desistencia = None self.v.comecar_atividade(DIA + i, 'ler', 200) if self.v.desistencia: largou = self.v.desistencia break self.assertIsNotNone(largou) segundos = int(self.ordens[-1].split()[-1]) self.assertLess(segundos, 110) # mandou ao celular a duração encurtada self.v.tick(largou[0] + 1) self.assertIn('bocejar', self.ordens) self.assertIn('Largou no meio: cansou de ler um livro', [d['texto'] for d in self.v.diario[:3]]) def test_personalidade_muda_o_jeito_e_amadurece(self): self.assertEqual(self.v.jeito('rir'), 1.0) # neutro nos testes self.v.personalidade['brincadeira'] = 0.9 self.assertGreater(self.v.jeito('rir'), 1.4) self.v.personalidade['timidez'] = 0.2 self.assertLess(self.v.jeito('timido'), 0.7) antes = self.v.personalidade['timidez'] for _ in range(10): self.v.estimulo('carinho', DIA) self.assertLess(self.v.personalidade['timidez'], antes) self.v.salvar() outra = Vida(Path(self.tmp.name) / 'vida.json', iniciar=False, rng=random.Random(1)) self.assertEqual(outra.personalidade, self.v.personalidade) self.assertIn('personalidade', self.v.status()) def test_cada_decisao_vai_para_o_console_com_o_porque(self): self.v.necessidades['energia'] = 10 self.v.proximo_ato = 0 self.v.ultimo_tick = DIA self.v.tick(DIA) origem, texto, motivo, _ = self.linhas[-1] self.assertEqual((origem, texto), ('vida', 'Ficou exausto e foi dormir')) self.assertIn('energia 10: abaixo de 20', motivo) self.assertIn('energia 10 · alegria', motivo) self.v.estimulo('carinho', DIA) self.assertIn(('sentidos', 'Recebeu carinho'), [(o, t) for o, t, _, _ in self.linhas]) class ConsoleTest(unittest.TestCase): def test_guarda_as_ultimas_e_publica(self): c = Console() publicados = [] c.publicar = lambda tipo, dados: publicados.append((tipo, dados)) for i in range(450): c.registrar('vida', 'ato %d' % i, 'motivo') c.registrar('inventada', 'vira sistema', nivel='qualquer') st = c.status() self.assertEqual(len(st['linhas']), 400) self.assertEqual(st['linhas'][-1]['origem'], 'sistema') self.assertEqual(st['linhas'][-1]['nivel'], 'info') self.assertEqual(publicados[-1][0], 'console') self.assertEqual(len(c.status(desde=449)['linhas']), 2) if __name__ == '__main__': unittest.main()