From 1a5fa88297c615ea2f6df72523e8a270de01bbc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davi=20Witalo=20F=C3=A9lix=20da=20Silva?= Date: Fri, 22 May 2026 23:09:15 -0300 Subject: [PATCH 01/12] Add files via upload --- POO/Guia1/README.md | 202 ++++++++++++++++++ POO/Guia1/data/records.csv | 6 + POO/Guia1/data/records_teste.csv | 8 + POO/Guia1/src/__init__.py | 0 .../src/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 154 bytes .../src/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 146 bytes .../src/__pycache__/main.cpython-312.pyc | Bin 0 -> 1354 bytes POO/Guia1/src/config/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 153 bytes .../__pycache__/settings.cpython-312.pyc | Bin 0 -> 702 bytes .../__pycache__/settings.cpython-314.pyc | Bin 0 -> 749 bytes POO/Guia1/src/config/settings.py | 5 + POO/Guia1/src/main.py | 31 +++ POO/Guia1/src/models/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 153 bytes .../models/__pycache__/record.cpython-312.pyc | Bin 0 -> 1395 bytes .../models/__pycache__/record.cpython-314.pyc | Bin 0 -> 2355 bytes POO/Guia1/src/models/record.py | 34 +++ POO/Guia1/src/repositories/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 167 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 159 bytes .../abstract_repository.cpython-312.pyc | Bin 0 -> 758 bytes .../abstract_repository.cpython-314.pyc | Bin 0 -> 1028 bytes .../record_repository.cpython-312.pyc | Bin 0 -> 1711 bytes .../record_repository.cpython-314.pyc | Bin 0 -> 3860 bytes .../src/repositories/abstract_repository.py | 11 + .../src/repositories/record_repository.py | 51 +++++ POO/Guia1/src/services/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 163 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 155 bytes .../record_service.cpython-312.pyc | Bin 0 -> 1228 bytes .../record_service.cpython-314.pyc | Bin 0 -> 1655 bytes POO/Guia1/src/services/record_service.py | 14 ++ POO/Guia1/src/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 160 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 152 bytes .../__pycache__/file_loader.cpython-312.pyc | Bin 0 -> 1137 bytes .../__pycache__/file_loader.cpython-314.pyc | Bin 0 -> 1445 bytes POO/Guia1/src/utils/file_loader.py | 14 ++ POO/Guia1/tests/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 156 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 148 bytes .../__pycache__/test_runner.cpython-312.pyc | Bin 0 -> 5184 bytes .../__pycache__/test_runner.cpython-314.pyc | Bin 0 -> 5430 bytes POO/Guia1/tests/test_runner.py | 92 ++++++++ POO/Guia2/README.md | 155 ++++++++++++++ POO/Guia2/pytest.ini | 3 + POO/Guia2/requirements.txt | 0 POO/Guia2/run_tests.bat | 2 + POO/Guia2/src/__init__.py | 1 + .../src/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 274 bytes .../src/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 266 bytes POO/Guia2/src/folha_pagamento/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 358 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 350 bytes .../__pycache__/desenvolvedor.cpython-312.pyc | Bin 0 -> 419 bytes .../__pycache__/desenvolvedor.cpython-314.pyc | Bin 0 -> 1967 bytes .../__pycache__/estagiario.cpython-312.pyc | Bin 0 -> 413 bytes .../__pycache__/estagiario.cpython-314.pyc | Bin 0 -> 1520 bytes .../__pycache__/funcionario.cpython-312.pyc | Bin 0 -> 3389 bytes .../__pycache__/funcionario.cpython-314.pyc | Bin 0 -> 4983 bytes .../__pycache__/gerente.cpython-312.pyc | Bin 0 -> 407 bytes .../__pycache__/gerente.cpython-314.pyc | Bin 0 -> 1787 bytes .../src/folha_pagamento/desenvolvedor.py | 37 ++++ POO/Guia2/src/folha_pagamento/estagiario.py | 26 +++ POO/Guia2/src/folha_pagamento/funcionario.py | 77 +++++++ POO/Guia2/src/folha_pagamento/gerente.py | 34 +++ POO/Guia2/tests/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 156 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 148 bytes ...desenvolvedor.cpython-312-pytest-8.3.5.pyc | Bin 0 -> 5824 bytes ...desenvolvedor.cpython-314-pytest-9.0.3.pyc | Bin 0 -> 6215 bytes ...st_estagiario.cpython-312-pytest-8.3.5.pyc | Bin 0 -> 5706 bytes ...st_estagiario.cpython-314-pytest-9.0.3.pyc | Bin 0 -> 6102 bytes .../test_gerente.cpython-312-pytest-8.3.5.pyc | Bin 0 -> 5809 bytes .../test_gerente.cpython-314-pytest-9.0.3.pyc | Bin 0 -> 6195 bytes POO/Guia2/tests/integrity.py | 32 +++ POO/Guia2/tests/test_desenvolvedor.py | 44 ++++ POO/Guia2/tests/test_estagiario.py | 38 ++++ POO/Guia2/tests/test_gerente.py | 47 ++++ 82 files changed, 968 insertions(+) create mode 100644 POO/Guia1/README.md create mode 100644 POO/Guia1/data/records.csv create mode 100644 POO/Guia1/data/records_teste.csv create mode 100644 POO/Guia1/src/__init__.py create mode 100644 POO/Guia1/src/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/src/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/src/__pycache__/main.cpython-312.pyc create mode 100644 POO/Guia1/src/config/__init__.py create mode 100644 POO/Guia1/src/config/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/src/config/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/src/config/__pycache__/settings.cpython-312.pyc create mode 100644 POO/Guia1/src/config/__pycache__/settings.cpython-314.pyc create mode 100644 POO/Guia1/src/config/settings.py create mode 100644 POO/Guia1/src/main.py create mode 100644 POO/Guia1/src/models/__init__.py create mode 100644 POO/Guia1/src/models/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/src/models/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/src/models/__pycache__/record.cpython-312.pyc create mode 100644 POO/Guia1/src/models/__pycache__/record.cpython-314.pyc create mode 100644 POO/Guia1/src/models/record.py create mode 100644 POO/Guia1/src/repositories/__init__.py create mode 100644 POO/Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc create mode 100644 POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc create mode 100644 POO/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc create mode 100644 POO/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc create mode 100644 POO/Guia1/src/repositories/abstract_repository.py create mode 100644 POO/Guia1/src/repositories/record_repository.py create mode 100644 POO/Guia1/src/services/__init__.py create mode 100644 POO/Guia1/src/services/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/src/services/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/src/services/__pycache__/record_service.cpython-312.pyc create mode 100644 POO/Guia1/src/services/__pycache__/record_service.cpython-314.pyc create mode 100644 POO/Guia1/src/services/record_service.py create mode 100644 POO/Guia1/src/utils/__init__.py create mode 100644 POO/Guia1/src/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/src/utils/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc create mode 100644 POO/Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc create mode 100644 POO/Guia1/src/utils/file_loader.py create mode 100644 POO/Guia1/tests/__init__.py create mode 100644 POO/Guia1/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia1/tests/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia1/tests/__pycache__/test_runner.cpython-312.pyc create mode 100644 POO/Guia1/tests/__pycache__/test_runner.cpython-314.pyc create mode 100644 POO/Guia1/tests/test_runner.py create mode 100644 POO/Guia2/README.md create mode 100644 POO/Guia2/pytest.ini create mode 100644 POO/Guia2/requirements.txt create mode 100644 POO/Guia2/run_tests.bat create mode 100644 POO/Guia2/src/__init__.py create mode 100644 POO/Guia2/src/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia2/src/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__init__.py create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc create mode 100644 POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc create mode 100644 POO/Guia2/src/folha_pagamento/desenvolvedor.py create mode 100644 POO/Guia2/src/folha_pagamento/estagiario.py create mode 100644 POO/Guia2/src/folha_pagamento/funcionario.py create mode 100644 POO/Guia2/src/folha_pagamento/gerente.py create mode 100644 POO/Guia2/tests/__init__.py create mode 100644 POO/Guia2/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 POO/Guia2/tests/__pycache__/__init__.cpython-314.pyc create mode 100644 POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc create mode 100644 POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc create mode 100644 POO/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc create mode 100644 POO/Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc create mode 100644 POO/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc create mode 100644 POO/Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc create mode 100644 POO/Guia2/tests/integrity.py create mode 100644 POO/Guia2/tests/test_desenvolvedor.py create mode 100644 POO/Guia2/tests/test_estagiario.py create mode 100644 POO/Guia2/tests/test_gerente.py diff --git a/POO/Guia1/README.md b/POO/Guia1/README.md new file mode 100644 index 0000000..e978c4a --- /dev/null +++ b/POO/Guia1/README.md @@ -0,0 +1,202 @@ +# Guia 1 - Carregando Dados + + +Este projeto tem como objetivo praticar conceitos de Programação Orientada a Objetos (POO) em Python, utilizando uma aplicação simples baseada em leitura de arquivos, criação de objetos e processamento em memória. + +--- + +## 🎯 Objetivo + +Você deve analisar o código existente e implementar melhorias para que o sistema: + +- Valide corretamente os dados carregados do arquivo +- Permita buscas mais avançadas +- Passe em todos os testes automatizados + +--- + +## ▶️ Como executar + +### Executar aplicação + + +python -m src.main + + +### Executar testes + + +python -m tests.test_runner + + +--- + +## ✅ Critério de sucesso + +Ao executar os testes, o resultado esperado é: + +- Todos os testes com status **OK** +- Nenhuma mensagem contendo **FALHA** + +Se houver qualquer **FALHA**, o sistema ainda está incorreto. + +--- + +## 🧩 ISSUE 1 — Validação de Dados + +### Problema + +O sistema atualmente carrega dados do arquivo sem validação. + +Isso permite registros inválidos, como: +- ID vazio ou negativo +- Nome vazio +- Endereço vazio + +--- + +### Sua tarefa + +Implementar validação para garantir que: + +- `id` seja inteiro positivo +- `name` não seja vazio +- `address` não seja vazio + +--- + +### Regras + +- Registros inválidos devem ser ignorados +- O sistema deve continuar funcionando normalmente +- Deve ser exibida mensagem indicando o erro + +--- + +### Exemplo esperado + + +Registro inválido ignorado: {'id': '', 'name': 'Sem ID', 'address': 'Rua C'} + + +--- + +### Onde implementar + +- `models/record.py` +ou +- `repositories/record_repository.py` + +--- + +## 🧩 ISSUE 2 — Busca com Múltiplos Termos + +### Problema + +A busca atual aceita apenas um termo simples. + +--- + +### Sua tarefa + +Permitir que o usuário informe múltiplos termos: + + +joao rua a + + +--- + +### Regras + +- Separar a entrada em palavras +- A busca deve ser: + - Case-insensitive + - Aplicada em `name` e `address` +- O registro só deve ser retornado se contiver **todos os termos** + +--- + +### Exemplo esperado + +Entrada: + +joao rua a + + +Saída: + +Record(id=1, name='João Silva', address='Rua A 123') + + +--- + +### Onde implementar + +- `services/record_service.py` +ou +- `repositories/record_repository.py` + +--- + +## 🧪 Sobre os testes + +O arquivo: + + +tests/test_runner.py + + +executa automaticamente: + +- Carregamento de dados +- Validação de registros inválidos +- Busca com múltiplos termos + +--- + +## ⚠️ Importante + +- Não altere os testes +- Corrija apenas o código da aplicação +- O objetivo é fazer o sistema passar nos testes corretamente + +--- + +## 💡 Dica + +Se você precisar escolher onde implementar a lógica: + +- **Validação → Model ou Repository** +- **Regra de busca → Service ou Repository** + +Essa decisão faz parte da avaliação. + +--- + +## 🚀 Resultado esperado + +Ao final, o sistema deve: + +- Carregar apenas dados válidos +- Permitir buscas avançadas +- Executar todos os testes sem falhas + + +OK: Registros carregados +OK: Registros inválidos ignorados corretamente +OK: Busca múltiplos termos funcionando + + +--- + +## 📌 Conclusão + +Se passou nos testes sem falhas: + +✔ Você implementou corretamente +✔ Você entendeu a separação de responsabilidades +✔ Você aplicou POO de forma prática + +Caso contrário: revise sua modelagem. +>>77f39f6cb45e487337a25f811b074ceb<< \ No newline at end of file diff --git a/POO/Guia1/data/records.csv b/POO/Guia1/data/records.csv new file mode 100644 index 0000000..d93a3ca --- /dev/null +++ b/POO/Guia1/data/records.csv @@ -0,0 +1,6 @@ +id,name,address +1,João Silva,Rua A 123 +2,Maria Souza,Rua B 456 +3,Carlos Lima,Rua C 789 +4,Ana Paula,Rua A 999 +5,João Pedro,Rua D 321 \ No newline at end of file diff --git a/POO/Guia1/data/records_teste.csv b/POO/Guia1/data/records_teste.csv new file mode 100644 index 0000000..56a36dd --- /dev/null +++ b/POO/Guia1/data/records_teste.csv @@ -0,0 +1,8 @@ +id,name,address +1,João Silva,Rua A 123 +2,Maria Souza,Rua B 456 +,Sem ID,Rua C 000 +4,,Rua D 111 +5,Carlos Lima, +-1,ID Negativo,Rua X +6,Ana Paula,Rua A 999s \ No newline at end of file diff --git a/POO/Guia1/src/__init__.py b/POO/Guia1/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/POO/Guia1/src/__pycache__/__init__.cpython-312.pyc b/POO/Guia1/src/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..508044149c0e1da12c8d749bf240946e280aa495 GIT binary patch literal 154 zcmX@j%ge<81RulLvq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!vUIkJ2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=3nE3e2yv&mLc)fzkUmP~M`6;D2 Zsdh!IK$94OxERFv$jr#dSi}ru0RTanB}V`N literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/__pycache__/__init__.cpython-314.pyc b/POO/Guia1/src/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72dd53e33571d4ded118fb0800803b0bfd875416 GIT binary patch literal 146 zcmdPq_I|p@<2{{|u76rSEJN6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*kx791|a(nU`4-AFo$Xd5gm)H$SB`C)KWq V6{sI%LotZ)iJ6g+v4|PS0su44AbbD- literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/__pycache__/main.cpython-312.pyc b/POO/Guia1/src/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f428612b362df54b091ea986c3d9b5eafc200da GIT binary patch literal 1354 zcmb_c&2Jl35TEC_yIwo~Xf{M`Y9AITC>CN1g7i=|Ab+H3C6qwi9vZn?S>A`csl997 zuA4ftQ4S#a0FpVN9sr3G2=&T8KzihoG=Zcm_XHPiCJ9oNTzGHom2>05NINrc<~JYj z&1ip($D_aqe-vK(Cj{^ZKLo_iJ{?_S;t?2Npc>TCDneWj)k1Z=ikXf-gH?fuhH!rt zfXX2t!sAgWf|l44GtyuDoIzfEg;Z>66bXG`RtPi5MdG@qRdp((2w#YdWA+{WjCf_2 z@gccEPp~Egwy}IX!gat62UY_GRs<1f!&)TpjAhVm2enZF?#2N+p>c+GXq@4Tq`sW#CKpF{a<-9($YqHeturfXIEAh7PCu*WtGXB#ak=O zMU^==qyC9A~M%e9(L{T+0?$il-4 zX}G3sd7^1Gnyx1~q)aRKGLjc|hAZlY12m!@BA(z9TIWWmS#upnVx?4{PUiAgOSf5+ zQ+iOYxujGe&VAQzls;Tu<{zutuuF?gv;20+p_Nj-Y+72QJ_WOkJ|y5WP#3x|Lr)7@-8Hradm z%Nu`Vb~=uM7~PJh_JnkQ;@tM+o4XU*W?>-6Vw#0N(!SEZe`!~Fy&HZup&U%7S%&yb z5B1MY_sU<(EJJ+eSc15+tz7;s_STEz6vU?-;=`)CZIkh9FP6wEoPnTJ8#LNfVqak=#3YE0xG;cuNzxekGDW zkGI}W_I|p@<2{{|u76W#()Z6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*kx79Fv@%mzJ3x6Ca2 cKczG$)vkyYXbi}rVi4mKGb1Bo5i^hl09s-rRR910 literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/config/__pycache__/settings.cpython-312.pyc b/POO/Guia1/src/config/__pycache__/settings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0fed221e1b0c294d41f357ce67001829af8cb87e GIT binary patch literal 702 zcmX@j%ge<81m6SLvz7zt#~=<2us|7~6@ZNC3@HpLj5!QZ3``8}3@J=43@Oa3nII~n z7%LeySzdxTe#sCa2+0oRe0~6AOlL@Ch+<4(h+;}*&fP|NE|4WCMwxhGeV3< zr=!?$*e8g^W$Y=8DNL)GAu>^%mCTwfw>W}ROG+~H(u;4gq$HLkR&f`lCg&HW6ze4y zm-%UO-QtLk&r8frjgP;@6(66QpHi9wV)Mku7nUaGKxLTnfw~J4OEPY;r(_m^1VP%; zGQmnYoE(E)<6S(1Zn0$LXXf4Fba4!EjCb?&ab3yq8RV2-4$f9Fp~b01#W7`xIVGtv zE~&-YCHVz00sj6V9AA`LkRRh-nwe-AQ(TlBlboNImYE(?40X3&L1hsr+Q9_KZ^bS^ zqJ`lGzhHlPXL)~pXZ?(#`QOwIIAQD}0T2r;B?M&s;;?~)id~T~kPC{Y aVvzU;W=2NF+YFrFS(q5@J~03ZupR&?zLd`Z literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/config/__pycache__/settings.cpython-314.pyc b/POO/Guia1/src/config/__pycache__/settings.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5eeec148bdc5b17a25e5551f2e3d7f4d8477f1c8 GIT binary patch literal 749 zcmcIiF>ljA6uz?!c9WEZLd1xGDMBhjiWpE^DUd>qppC8|I=DR@j#I8m?Q(anDH3u9 zgw(0()OIQx&D53uk)=9DCRjkqz{;JSN`UCd4c~p=z3<+8e!iO*#tT5LrSFxsk81y- z#p$v}WO!YX9#{bgx49aSyg(Q$ zrZAVSR#y9WI{>ZmKebl>#c9`JUg_^$IA_$m^pDOQ1d&lU^N1)QQxuVQ*k%_n`n*$4Brl5{W*$$EgXEMUAIwd1blC5&Iiq&td~G44>tMVE#_ z7^$!kse~Iuyp(pEGVRiNIyAfM+-oe(;--tFwHDD(jx`%k8~B0ycve<1=7I?7Vvo6-t#R%x{>!J=G6CE3k%-En3CHbXTIl0VTZ1IeDrCP z8(U1jk__|^cvHc9a8kawlWZqD>2|u$4wHlAFg-|**m2TNj?;en>Gj~&+~BG^C_n1W zom3|F>|J}Wv|HL=`mlNQc2Jpq=Q2I)EN#tT#Z#WOn};r|GwDp_W1C@BCH4R06AFHq S5W>%3?5AbGnITY+-T4JyXP*!N literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/config/settings.py b/POO/Guia1/src/config/settings.py new file mode 100644 index 0000000..bc893c6 --- /dev/null +++ b/POO/Guia1/src/config/settings.py @@ -0,0 +1,5 @@ +import os + +class Settings: + BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) + DATA_FILE = os.path.join(BASE_DIR, "data", "records.csv") \ No newline at end of file diff --git a/POO/Guia1/src/main.py b/POO/Guia1/src/main.py new file mode 100644 index 0000000..0907e9f --- /dev/null +++ b/POO/Guia1/src/main.py @@ -0,0 +1,31 @@ +from src.services.record_service import RecordService +from src.config.settings import Settings + +def main(): + service = RecordService(Settings.DATA_FILE) + + print("=== CARREGANDO REGISTROS ===") + try: + records = service.get_all_records() + for r in records: + print(r) + except Exception as e: + print(f"Erro: {e}") + return + + print("\n=== BUSCA ===") + term = input("Digite nome ou endereço: ") + + try: + results = service.search(term) + if results: + for r in results: + print(r) + else: + print("Nenhum registro encontrado.") + except Exception as e: + print(f"Erro: {e}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/POO/Guia1/src/models/__init__.py b/POO/Guia1/src/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/POO/Guia1/src/models/__pycache__/__init__.cpython-312.pyc b/POO/Guia1/src/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2285cc1d7873a863d22504288650b51d1c3561a GIT binary patch literal 161 zcmX@j%ge<81RulLvq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!a&Wea2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=3nB4r7)STj&`1s7c%#!$cy@JYL e95z6~(wtPgB37V*j6hrrVtiy~WMnL22C@K)&L}Pb literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/models/__pycache__/__init__.cpython-314.pyc b/POO/Guia1/src/models/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a7e1ea3ee097de919629c86f9fdacc211bd3332 GIT binary patch literal 153 zcmdPq_I|p@<2{{|u76W#()Z6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*kx79Fv=$lA2Q-6Calh7 zwqkItre$>7;ChW5h8Hpsh>dfx3323H9OY(>WMb85I_4SA>|9B3FDiV?9PVkW*`n=5 zvYZQB%3Qm5td8BP@U+H2?UD_;K^S;}Y$y=HKa;lROshjnl(6gUAs=8;jC1WvS1kp+_0XWdxP z+TO(V<=baDfo+)yVs)H0~POao{{orPb+N56|LAl3bj fPR+-`jFVy*a(-LA;51cA>0c#Dm+2pZ+Q0G-QeG8< literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/models/__pycache__/record.cpython-314.pyc b/POO/Guia1/src/models/__pycache__/record.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..645452895a2a019254486b147ab2c065afab97ad GIT binary patch literal 2355 zcmbtVO>7fa5T4z&ops{GIB5tZF*u}6a7&;qk%}mPf>7YlKo>U&bYZo47qQ6Rb>FTd zVin0kl^P_}f;f15yvDHzOkj_0*Z?wd2x=1AWrYn>RB% z-@JJ<@4eU6*$z0~sjj>Ds|4^TEgB;fFtvVU%Fqi#pgGke0HIKWGkg zP`iK&9sfH6o}hpyo)tW4JvcB0I|W7PgPg30NY{CxGhs#QgYm$N7r}L?W!;ABaLZa& zB7NXRl{T+^3cLrv644zJ`V0L<`|zWTJJl@157~O&^xJg9V5aM)MPIUP&zD?}As;#Ku)Oa1 zotl=->8@*7Sx?hk^0B4tk008te(svgRj21XJ?E&O7F{c=o;ZG7JyNvv4^)?B)x2Yv zIajR%ZZFLFF-_BL+wpYI)HJ`RzP;_OLUQkJLGrQ;E073peNN=waFwQ|lYIJlCl}Vx z3bKt8r3LYr1-W(wvsH!xP#al;DPcU|3!zNtEbQ8i8H-WIRLUkFSOtO21tBAj22x`^ zS!Ki%ZGoU=YMiek?wVP{pVZ<{dc~jg2L3{;{!SgRn>&AfY#Fe_jgT|1MMX=hE4*`$*j9q7*$UJW0HD{nX7( z^9QRk#Ja90u6^{RdvHNp?jEbe#-7D{u6wsiH%d3Zy2~E*rBPK$?pyBOUy1F17GJ+G zdS`5L?DmfP%A@`rTz6=>d!iDXc-qr@O@7?F@z&`Zr*EqBp=<4rH*CJsx!8F-J|FtF z^W}>qBnG}eR*8?i0D*!azn?63AF0HSR3(!9?RH?0S2_+3!S6%KgZm_Y0ilQwY7yRK z^(%A=P6Ue9X&9D-$+W<*caUQnadPR$5uPJPzxvT2J(kf+YQikT(|FH!m#$u#kF#~S zeiLA}34cWBKAafUPb)B;oZk@u(-HH?@E!=DOIJ%3dE@`a-mn%nFPN?XJE*H9#kUH7 z`Re70JosOD3Y+JAibty8rN36zWB8DvrrES;91PTms0lUJt21h(58LQ@D7DvP+iDqm zOY*i9rDyMGDK@$-6-0|GaWtKl__5X#yw*;s1(;c2|7wA{UW^L+BFT| znqrQ4d}F>W>bXD@*R=B%bG@8po3?{-4WI{KE-_I|p@<2{{|u76W#eoW6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*kx798;89kYAixl3$dWS{xG}pP83g5+AQu iP;}bI@BV!RWkOcsBg(eLE literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc b/POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75a73ffdf35f2cab02f70cce6448b7c0973e8b06 GIT binary patch literal 758 zcmZuuv2N5r5S`t%FD9IWLLwnVa}t#)f`AU8NFhk+E&++gvb1u%8|A>p$F2|QQc>JL zTz(-+#c#kLY(pd}x&uR#iW&Qi62VG-`^Gc--t5koFkA&(pAJ^ue8&A71>N$Oq<(;8 z4hj^@pRiQxJ146q~{MvNHBC=Gs5vO3b{!e|zNQZtpDBU+HmaM^$O28M|tMoLp)T zVGdI`W5Y9unDea8k1UlAE?@3GOy=9_iu+=U6Nk7Cin;!LBB=<&a1R3GEV%;x^@Q> zV8+})h`6EonOg{!&I|_TCT^~0b!xKXle_VeFP_Ps%D+SMu|ikYtth}Kt0=s2s60wH-2#DhqZv-=7QLw*Rj(l zKcP!CMNLDE!Z7ljNDnhZQmuERe%_zk!< G+J6AH@2pP% literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc b/POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb28955cb911383858af23722d85d252c89826a4 GIT binary patch literal 1028 zcmZuvPfyf96o1opYe5zeSP9Vtg@mNRU<@3LAx7i?CJI_3lGtT3bW5n|ZgFPzu(v&! z_!aac@KyW>b5Y}olS^uVqwlr5ghb}>n>X+8@4YvRqt#)+v-@ZK<9ED&(_?TdeIb8< zLKpTRU@u^kX|`!;YZhv79|CI{0=v#u?9x};fin+&<%FKTW$d-*>t;O5NFkWkz*VFR&5EFKuq%=o>qr zy`X{|Tr;uOuN%ZinM!mfI}y85oMf!;KHH0M1zYoHFy4Jwlpx( z)N_I^{PIR}6rf-|U~Zv;rk3ABSY=($G2bpXNZK|9{sZgqsM4EF&u5(>^lOjeq7p+#Ng^oElv)2&5>Oh}JO(9%# z;T%|{dP?wZxwzyQ8X`(QIM+;GdT5kG2)-pLot!`@C@n0Mlw1`H86BFLYsi!)3YVh< zRIwg zl6o#m=a;%OlFC*n#g^|FTkJ=Y(vat{4y)Wv3cHe>7u%>Q*f NR{c7826z>@{{hmF?-~FA literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc b/POO/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f76d38a1756ade4d7422d23b0b37569b6c91650a GIT binary patch literal 1711 zcmaJ>&1)N15TCdER+3fAQX&^ewi~N)+Onk>f^%wvjg!z&D0WE6MW`%W?K+XWvYhwU zGB#4l!3T$?I3@+;NdJwW3NKT!3E2&CqGO+XJKo|`yWn4Q7s|5em&Gz#BiGzQSvV-gKQDUjmu1^= zMInq2ITokr@MB!+;6jc$kkcII>a&`ot@0dq^i{|i4p$ZfE$YWXD$M=g|AL-b{D-w* z`!@^iw3M4J z&Ayts^lARObcM`UY|nS|mtFa-UtY*xotdEzV;9Q#D~m<@TwaPoo>X-^MOUIim!r0X zH#WAgjK8yr^F`mXRx)oMaIEc$QUNJsw_$&9bdBFl?w=Z5<3A)0(FTRiaZu^OPaXa@ z6zbr2d~@Abgg&Aw%<)j_=3A|p8mqF)u&x!f8&J@`ejlKw`BaJ`pZ=t%is)rfYR93j zk&dgb?5zgc(C&_M%v945f_76<4XSm+Ty6dp?qh225}15C(27pL=k1akL~X|ru9Rj( zP>vwxVUt+}SrPA`D(F0cUYz$uFG{8^5@g_x?c0Ga%1e@p$!4>nkL+Qv?Rm#szRHU( zN-OioZo{)==8xo=z2uqA^S?|!oP3fTU*nAkoEm;%=$ZKQRQgDVMEb|^d-B2gjph3j zo8z06ho5ch+h6STJ?))r>bMKhOEhAT>R+$jsqMywUp9NtD(Ngge>ioT2i$i>>9vNA zpig1Civl(DTnAM&v}mifB5H6P)?G+mAS7`twByi!TkZa~s93tdme_fMwLbMIEYvQep5H>&r)+e?1%Yyb9%$C;hXHL3==dK;xw{HAZV^tHwv09#i$wN2(ndZaLpLn96bbFnz4xSUL$1~@dx8afJ+!l zVN}9dd~n9PADl6}^+tC+If5D~I6+&nO4pMZL9bFcIPa2u(J!J|J%}^|2ny8`RyRsg sr{Y(!3*k{G#7F3$u9QQ_8aiX_04^QC*#r3Gh^JY6cfkAya8<$o0!#yaTmS$7 literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc b/POO/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1dac0c003611addffd9d9af6737b38488c21d006 GIT binary patch literal 3860 zcmbtXU2Gf25#BowDbNBE(jf6m;fECUO8~ohXdfvvwuFlV1Za!GZ*ru@PMclrqVD>lmHEmhVgp)yCNh$4&<8~@^{ za7eVpPON)IJ%=P);&o}%d&p<|I*H6E38pR+a7N*&EJBb}Of{`u6wyrF$7#b`Q3%i0?{g9a+ER(R+7 zbLX6Gs;XtPmaW;ks?vvG>HvJK1By9vkBGvH!d+here~G^f7j!-*I)$Ud&de=W$&*+ zV~%X>Z31^yLvROhIzy$N9GuHU`F^WLDq=H93Njfg@rFw0JmIezRPHPN@f;m#d}Qod z=Ry4jVbI!1D7r}}=r~D6zClQ?>Q1)SH7S%=?klb0-so5t0sYRBId3N!gRVN#0sHD9 zPk0RBvM?SOo%(#%NLv{_quH8Mm$qh38d)Pd4LxH2JROZO-$d2Vm>_#NEF#CaBj10{kUa1dVeDcDROQ>J5;YhLm$a1~1RIe24CkxUf z4TD%3z6zC%W$iGqG??-Pu?2}GJ+G{oGuXaQ9Le>byeeQzZHt;xa+afxix6M7U z@*%+>Qc^sy7KO$fIWA|B%c&m@D_h1UZkZJ4y(~IGwW7Hb08Bt=U|^LJ)6G+~2L`#< z9&-&dpsHZEuotIg3)S5&t~M5PWTmy|&G5=2t@F~)L$1OVC7{0^J~-*X8mji+fg(vJ zB#@|~vP0$szDc|}P6!tx`@yNjHj=8Va7BgeYAv_GX+=e-X^YkEa$v}LV08#YwKRcy zsG+2%tP_C20T&FmmhK@@l0rk_C1BWnXRJ&GeF4wfEjopC~0Yt{nubai7mK`a_Ap{2Wo zW|~_VC0`x78bE^m5ek5&aLaPI`$o8XVd(v57N04G2j?Yjqi=>j-QGNZU{&;oT5d;U z3+#iT_s(7ExpL|cJFl{9Pk;1!F*^QMXhm+k6nZ|)TH{CGyE=C5wZi1_!gr@`PO61tFBM+03OQD= z&)>|wUa)?+O2|I(fC#^)XT^1o7-{&zM4n#w^;4Cxuv2jZ_p(qYHZ~c+}u+y-T3@^&tN}h(~z++`X@Yduv{BaQM5l z5l3@EQkbYXZMmORB7IIwise{44dZr@eu%66ggYdfK@EY^FM`ucRclFGId0i8{?po< z=D^riL;uShyQ*X?ZwiA0r#-?8p2H*qQ4<|L>4i{6Fk~ggjVxybprO3?Ql0^D1DS1Z>Iar`;W)MlyXG?pq%%~bg}E)$EEB4rB-Jo-Sm zVY)`sr?*IlFy&^L+uV2aq0#HHD`yHFiCfzfAIHAp*zrcBQ5czw`+3&lcv;RgAhiY& z3J6Rn&fs_eH7F)CaUX{xx(B&F^cRacK>*CWX#*-UN1${c^f8PNF@&XkZm{&ZDmu+y zqk9(${T2#{@3+Gp@7Tp~@4WPRr0G)Y+pWLcG4K0FxM^j3)BNb?P0jN`Yn3%jNPp*1MsOw&U$lHI$ zK52lHC^n2~;Tp>tIxa%&;b!X2BU9gWB9 zAV*LU_8|cXs_KlD$wS(s;_Km+yk?eq!YU*cl-Z_{)w32nCw77`eF}?%P&iGH3c*9e zNUNG{Q{!ab))`C^sY;g8x@oFvTyW6{al<`Rif6_Pv|;`{x&ITu^m`(tMDQ^2wtW!@ zdE4)G05E-t=;UgTQt>)B;q8S7QGey}0}rBpt@OsLdJ<8zKqrDjVUxPaKmt=EH*_^2 zKW`hr=GhYl8J+TY$1Td$axbcik-U^T4ZFv+mny)+Eir`JRgWMDpOS{ZlLMcT-p|Oc WfBNvTwH}NKt%c_JmjwQNmVW~SP8@Fl literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/repositories/abstract_repository.py b/POO/Guia1/src/repositories/abstract_repository.py new file mode 100644 index 0000000..f09f5db --- /dev/null +++ b/POO/Guia1/src/repositories/abstract_repository.py @@ -0,0 +1,11 @@ +from abc import ABC, abstractmethod + +class AbstractRepository(ABC): + + @abstractmethod + def load_all(self): + pass + + @abstractmethod + def search(self, term: str): + pass \ No newline at end of file diff --git a/POO/Guia1/src/repositories/record_repository.py b/POO/Guia1/src/repositories/record_repository.py new file mode 100644 index 0000000..5947722 --- /dev/null +++ b/POO/Guia1/src/repositories/record_repository.py @@ -0,0 +1,51 @@ +import unicodedata + +from src.repositories.abstract_repository import AbstractRepository +from src.models.record import Record +from src.utils.file_loader import FileLoader + + +def _normalize_text(text: str) -> str: + normalized = unicodedata.normalize("NFKD", text) + return "".join(ch for ch in normalized if not unicodedata.combining(ch)).lower() + + +class RecordRepository(AbstractRepository): + def __init__(self, file_path: str): + self._file_path = file_path + self._records = [] + + def load_all(self): + data = FileLoader.load_csv(self._file_path) + self._records = [] + for row in data: + try: + novo_registro = Record(row["id"], row["name"], row["address"]) + self._records.append(novo_registro) + except ValueError: + print( + f"Registro inválido ignorado: {{'id': '{row['id']}', 'name': '{row['name']}', 'address': '{row['address']}'}}" + ) + continue + + return self._records + + def search(self, term: str): + term = _normalize_text(term) + + termos = term.split() + + if not termos: + return [] + + resultados = [] + + for r in self._records: + palavras_do_registro = ( + _normalize_text(r.name).split() + _normalize_text(r.address).split() + ) + + if all(palavra in palavras_do_registro for palavra in termos): + resultados.append(r) + + return resultados diff --git a/POO/Guia1/src/services/__init__.py b/POO/Guia1/src/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/POO/Guia1/src/services/__pycache__/__init__.cpython-312.pyc b/POO/Guia1/src/services/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7156b3400d03c95edf785d73c6374451cf8d4037 GIT binary patch literal 163 zcmX@j%ge<81RulLvq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!a&oqc2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=37@*3s%;ePKnE3e2yv&mLc)fzk hUmP~M`6;D2sdh!IKqDD}xERFv$jr#dSi}ru0RZsEDG&ev literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/services/__pycache__/__init__.cpython-314.pyc b/POO/Guia1/src/services/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d71c282e1448abc622a2253d54485cc5f8f4da59 GIT binary patch literal 155 zcmdPq_I|p@<2{{|u76W#McU6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*kx790Qau%S=u!j){-Y%*!l^kJl@xyv1RY do1apelWJGQ3N#30RWXS1iJ6g+v4|PS0sy#`Bt-xK literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/services/__pycache__/record_service.cpython-312.pyc b/POO/Guia1/src/services/__pycache__/record_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29288bfcc275c671ade748d6ba8a812eb45dfc94 GIT binary patch literal 1228 zcmZuw%}*0i5TCanrBIqhFhGKYMh#*4N{kVRF?vvgUJ3#A&@|bs-G^-1vh}?!u}u%e zaPX+{P>*<%@K2a{^ipgLy1|nt17rbv}%S%8QU$6Ts$_hPgrwEap98Ic+O1O>l>fm zJGSNOim!5y*+swWiRqN+ea2iCf*9k}WVuzuR6xisAd8wP0Fw2iqH^&pc%h5HncqOR z3E#E8*Iupirt-GB&Atri2fdf-!?TUvxqA29DLhB_w9##^p-tA~lL4Y>oEB`bb+bSX z!|yVTf@_sW>zW_uFf literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/services/__pycache__/record_service.cpython-314.pyc b/POO/Guia1/src/services/__pycache__/record_service.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5942cbafc4ace39f14f86a30b4e08709cfc0d58d GIT binary patch literal 1655 zcma)6&2QX96o0ep-8f%$NSbV+DM=e?TQ_YGYG@-=6(oe9l}HyCmP)u8xn8Gn<*dWZ zY^78j_JBl>AP$IIdn5k^68}J=Ac{ss960sVkCjM|yf^l4HW3F#@|&6W;rD*;W9E;H z4gs#4&&KZl!T|oJOLtlMp;N^}8&<$$SK(u(*bGdEEo7^O0%JPa8 zP$k2+48LUfWv{FT>Y!|I0NvYqH1m5S68GXT3K0{~M~j>m@$1YYxy;(=WTmk54L}3A z)9@)yz751BO(1SHdTim16I29g2ioA?Wzoc{%-VTAy2 zBrX$_G)YMFu$?=RA`xPwrj`1{!RQZ(4eSb@@DQ8dEe1byn*}p0N$>Cf0+co2ZGwOoQJmfY1-pKz1@;wFdH}T{rV`08>wsQ5>8;ep@-^0(uzJ5A{AM6%Q6Z?xQ27 znknaE5{<>{L`;~I_?F=G#~}|CqP^Wxk;I?8*7w?k5jHDFzosLoR_|vGLGvYuP+jDk zNM3!5$o4FJ8J^Sg@UqNG^Lu4%j(?~_O#H@R*)8f*_%to_<~)uhUT7ftX5YL9#$XFF j<81IRXJD_0dGtvENgBTAMaI~l@ZO#^%+7ZJiLv_I|p@<2{{|u76W$J7d6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*kx798+47nNu7SAD@|*SrQ+wS5SG2!zMRB br8Fniu80+A3do*f5aSawBO_xGGmr%UHKrpE literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc b/POO/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b5ca6a21d9cb8e3b88c17bad2a4a743ae0d4df1 GIT binary patch literal 1137 zcmY*Y&1(};5TCbiH($2eMvK;lx@tY-(4vSaB?fB0E>cDD&=6Rb-B-Ic&BnJct*xm@ z^$#d`s3M}^MX85^9>j|lFM^jqJ*_zip1jpWD6|*nZL&pY+2790Z)V=So%g=Bw(%JY7Xt888lk8yrJNvpr4F<~`bO{6WOaRQZ9 zV2~p=bktYf5-a-D^5*=+h+~OsESQX1a6I96%2`dg zV$3ZUZCL?FHhRZmCE>W3Wyd^|_qdfW3#Z`agL6>`4#_}i!H-GRz#bP5%8r_+XCQRS z2D}Fd_hCzo#GqVLsd*3Iu)}4CZ`=s}ky4l^o5~&^Tc|7*0vaKPv zEd%NjcK<}6<9HoNe3aCZJ=Nax@8j!ttEu75DF>RhOg=5V!G40yC16Sf*2(O`m2>g%)`QHPO zm%{5ocnCkV&MhUTWgidM0Y422k>qdb;F1rb(+Za-xtV@cY5^rn?!+?9ezH7;ro2pE U5&<_%$ahF=tNTc{4hTWcU*u5>S^xk5 literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc b/POO/Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f524187a3da598ebc27fd7935f7579546c21a20 GIT binary patch literal 1445 zcmY*YO>7%g5T3Vh?buGz#0J-i;v}0!Dzd5;K_fLJP9V)sg#>9?NU}_aG`Ha>uuGiqkfb)L9EQU{jm@1fYS^D!jqA(f^z5U3i|d)E*E%$#0=E(X`ce zjU_x%vZf{3tx)dRDj5{Q@$D#Tc#aYxBK)aVGP^uyy%o7KvfjR>Y(KPKk0Z~qu3Wxs zU5Y*X1uK${6)Vq=tkk!kW_qr9D;W^N4uVkG$`vB1{C|ye#}!!&6FrOMaSM(hms$La z$mh%HUmN9+-kKOXefZ-2a_t$cLkq^h>eU19Z(^@Z?LxQu^GvW^mS;EDp1mH zgmcF2@~V`fVTXqAO2h8J=8RfjqK8d4NVpT-ObRPFK&DFro9Mn5sia7~Uk}w<7zYjV zAd~#+2aelRUKmI!Nllkj?L?;;O0u$J&D@B(blNZsNkvL>G+ly%JacTEdcq7sq85@C zJk`sKtI6W{0uqi64A4=ZDL*FO8`C;3&T^7faO=&VQFlC;=;ZB?uYx;<%817{=mxN&H>49^=0r!PE>`&793whkxme;q zmNLkH3+uI9k`p4ZcW848LSU0(+*?6AbtAU@u4YJxEl)*lPM+u?Ynr5G?wC#xm#RA5t9S0PC{Lq;;zT7RSTn|cgTj&C&lcN&B(?b$ D!hlE_ literal 0 HcmV?d00001 diff --git a/POO/Guia1/src/utils/file_loader.py b/POO/Guia1/src/utils/file_loader.py new file mode 100644 index 0000000..3272122 --- /dev/null +++ b/POO/Guia1/src/utils/file_loader.py @@ -0,0 +1,14 @@ +import csv + +class FileLoader: + + @staticmethod + def load_csv(file_path: str): + try: + with open(file_path, mode='r', encoding='utf-8') as file: + reader = csv.DictReader(file) + return list(reader) + except FileNotFoundError: + raise Exception(f"Arquivo não encontrado: {file_path}") + except Exception as e: + raise Exception(f"Erro ao ler arquivo: {str(e)}") \ No newline at end of file diff --git a/POO/Guia1/tests/__init__.py b/POO/Guia1/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/POO/Guia1/tests/__pycache__/__init__.cpython-312.pyc b/POO/Guia1/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4029fa49e430451318e97857bdcbdee513b4004 GIT binary patch literal 156 zcmX@j%ge<81Yg70vq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!vUawL2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|n3B}ulH!>7_{_Y_lK6PNg34bUHo5sJ br8%i~MXW%x7=gGL#Q4a}$jDg43}gWSq{k*W literal 0 HcmV?d00001 diff --git a/POO/Guia1/tests/__pycache__/__init__.cpython-314.pyc b/POO/Guia1/tests/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74b190c76f04268b6b96420064f9e03481ada412 GIT binary patch literal 148 zcmdPq_I|p@<2{{|u76W$0`b6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`7*mp3Tv8kpAD@|*SrQ+wS5SG2!zMRBr8Fni Xu80+A0?3YH5aSawBO_xGGmr%Ui$Ec1 literal 0 HcmV?d00001 diff --git a/POO/Guia1/tests/__pycache__/test_runner.cpython-312.pyc b/POO/Guia1/tests/__pycache__/test_runner.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5cc7ad8300e869efaa348ebcb42884e54da251ca GIT binary patch literal 5184 zcmb_gTWl2989uW!sH(6_Bva7`q*f};o5M@1zU*dg*_k?0)bP?b$Bq=_y!1b3F1rS& zm#Aa!xu5_1bI$*L|9|Fhfq);u^XK#4(I-&)j8vS5vkPlEC`=&*DNG8DF#`-k%AS;G zj2&QUnN4v69JH}1et`F&lStvNB89*2u_O#sC>2-HfL9e1@5Q|c;TjK8EAHFkN5giZ zEOYu8G|5h~QQ@DYFUpvKSJZ@tm9r|oluW45Ae>bVBbgr7`x0f-5o1@@_Ca9^sc3*v z(11r_Kn+&$K*}jBq&!g+)Z-!bPF6&{roUg+jaM@1w2Bjs6e5gl6AQn!acG@F25Foo#dl@dCe++gBcZ$l>4?OPW~42AEf!5nWa3(D2(E{Pu>BZ9E!U-8Ud?~w2o49 zaOzg>tO|3yPLHwGDJiVs9^g09iUUKjwQ^SaHTsRmDT4{1XhomNDY7AFw_<7ldfb3x zQkxU{rFF({@}#C`gCvV%dU(y_lTp9v(R7m=myHqAt0Zw+9#c&r9v@1k)Og(FMzv(x z^wCMA2@@?$uWlKa$&ce?+AzZjIhDwyWJ9&)jmY{))MIkGni?{N3$m`pL9|Y+K$6zG zdfNtH1qu4#B{^lNgU40g{+18oX+3uO{KOQdb>?npiuL;Zb+wRofuD#QE zyK#EtK}G)X%fSQ%QbuwdY{yXXm>y+t1SIR^y(L^j z7Gc5mvca;0gL;UJ`3@v-WdOp=m*g z;yReKVZ+Hr(GC9x6uxf5eFVh+B_%oA40Pgda?U+G#dGmEaJ5)=ux#mIC(93% zSRDowrwvWI@MuO)!Woj6&DNcHxlMXS9Zu>7)^sUh4OBEeE4|cn`czMw)TgFLGGh|V zr(;S(vb*gOCot9|S#x@@J64yz-6chNYDkz6pBWlfjkugjxmLucRG^X*mlNu^k<`*r zmfD8tb*zk0b#io)WLXMsAWH8jvlMD)&zdJOD?I^;Z9NC(g_af0>+4>sX_!jgN-fsJ z3N^7}&B1FYmqS%ITYr{&PyQ(M{BmV=zUII}Wy@nyIJ{7K(rT4AAMU4IVNx$$C80L?L5NE-0yH)a#+wH8rOXOf~@RoA@!zT;E@2ie<)3d<^&R z3|e%gQ-fy9r0_X*6N6^oW~o6#zR{qYL6Bq6vGdXo2^GnYW*^BhAL5Jw3Q@4@Ropp2|!IxQZYH|T)ncQU{%-gc4!CcB?O6gkTDF#M83{J0w}Oy zunlV2rl(=>HDpZW=s$+U#zObJaCC*+;_G}C3!hdut|B(D?IyDnj!YfAb@08GUmTh4 znSJTEFFn})r|2J|%aQtg!^!!`sgENKD_$7+g&zf~@>RVH;_)YsEvR%-sI)$09_ab1 z_C>LyAa+owbgt{WK#dzc6+O*pE+Ue2J58H?$3pB}Yw(z#{m{=td2_`4{{M^^=Icn` zrFBr(ejo<4kqWf$#))OL&(aXRoc1@+JH_S+8=IS;OyNm900?w3Irb8x`xGzDc}1W(bG@w$b3W${81xKs{iVK11g@ykS&AZ;E0eM%$8CaK?rn}D z7xFUXihY?qAjm=Pi|3_d89gBbe#WG+M<39z0N_O80&qG0Q4QP(&d8E%d8Zvu`yd@6 z2>_s^rW0D4B6gjTNI)uUB#4krM$YbZ@$QUH!f1k5O-jqs1)@Nv3A7?Ox72w?6=^7w zPJlm>(~6d@EBAAb1nSy+Pb0d*ig>UD;xT!1OcpZvls2Ja3*5Zx;fQ)VhI<_{IYYf{ zSU@My3IV!}^hT&=cR!8vO#`bK4AuV%iH-BtdExL1SLKT>iIqP;{qE^Sac@D~J1_40 z)bWAQLQVAE3&on&YbPJuUhvJ2LK5|YZS$4wOO-X05je^Sb@g{DZdXi)Z;R7!&Q8uu z7U~Wx*0vUETZ^?vZgNZE`sqj^y!&4D1Emmcdzko3!Rs!|aFc z!QLSID9A&(FDj6W0AW~fV2K{{ZYF&`;T$8H#m^G2i*}z<+fy6Is#Ml3X zn?k-aZ@F2x=^~mj-1t5R9}t{R0*BB~xl+)1jT?fy=~Y2toqq8DaH|CW&y2bp1?$^S z&gC!$U9aXq8~FGDf6i>+LuPb~GrE*JTAc-EXo1Lm!o#3*z#$-|-U>Q_FL-+dcrmolq zL#!rSTZ)6}#TQHD%G)M^QF=)!mAqiGW6B|u)5am_<&wa9W<_Qk?&qrM8&NMS$ziy< zQkI~+66H-Fy>iowxIkpY$$UOBl1X2rY=PT|UJhj(wJewH6(-5|NauA(K74!RF6v;y;;UvL-lH*Io^~1B|=ukeS&u zMwLpHN_EvnwcAKe9;$#E30LZaRaJ`Bhf0_}^bx`q$dpJ?+o~<+rRUt)Sr$x` zD(Yb0xxeS0z4v_IIcJUpi~R(i+Na?gWkrO1ferWJbCoAQgUSrKPNK|3a)Gg!daSb- z*$bS-(K>gLw|MB|E((@VK^jPuuOd;QopmHwo~WmaSl(-5)Z6(6A<1e&>c}-u18L7~ zF;teT6ujKAdXU>l|I6aPaa?BX;;5R?jpP;8cuPyD&>>z?ElW#}n}dl05roM#p7cUR zfgf>=SWJ{y>~+!NDv1t12^8a_ER;f&gVKYlTi&Pur5N>Cz7b;iquxd$i?)AQHLYkS zomP#6D;YPyBjgAXpBT_PLt@xRpP}3VxNUq7356}E{w-E`Tq*52P2Bes^9|B`?#iwA z2%JfjX@}o{&j?B9b&M4|eb_rhO~q|HZ+BN%<8?=3C2lRs#_|{Yt+e8zysMSFQ-HLw zZXHZRfSd8yd{VKL=@Nrlg&DWtp466v`IgQ2Z2?>6bP!*0gWg`t)XhQJZ?n2-^HYj7 zVSAIBkya*ETa3rYw3Hf;+x!h(OWQuW3cCzE9ouUZGML3v?e-+%QYMLFMzdm<;rK%m;feo>EJs8fG zG<_7EzdCnyJ~kJ-f9S#arL(WE92i+Cxw;g7V=3_c|8T6&{{%KB+rWUwM8WW5s#7cv zlqlJ{HZZ1~vEh36*+M*w=S|QZC3&`}M`O&J+iv4g2F!w;uJ!ly^hjslINSgFaAfe+ z%hK@KEAUT(-a(l+N@1y8MQ=EzE6Mm(E%;Jtv9ZXr*%V3+O>4lR23sJ z5uePYENu$R#!`(*Q)Y~EkZj^FZ#F7%6AtXo4i?-Vv=Jrdcc6fa6N{IEN3!D4&&9x+ z*t9G*WyR)otjo)yoE4AI`oU%K;HoGaHLzyek>gR(Bj2Rbc0ckxcxeA4AGsF+T#`TL z5yri~>!kBNAn_oQc)?!zaX=;CSU6IMR~V5Z0xZl%_1Qomvt>Nub|ZRyhJ;v7IspRT@q>68>z$2HS3 zbW=(=bCS9_EuD)DT!@^K2G#ULW>SKsbk5e4=>xeLXAMJ_6x|&$@^ek;Sg$lF3)G?v zyjVLlu3B*=mCBnFmr{XF&c2;crz}lR%N#Wl+v}PeqnZebW=WzZW9&gG`wL8l8r;iv z3ci$>2`F-AbUZ7zZt`AV-+E>3-PE1bT4mdEW!p++`>pdEq0-wOzx?t0N;Xu#5w2LO zJiZ!keT0?H)$qyZ8=>l_gz@!l1WK05Pd;dPP_|Usvli(6B+&cSCIZUA$X<4%|!~xdajmenWx1gT=Fr#7FiOj&m+voKdj) zfV+F%>bU}W{4n>D)w5GvABVD|w6@LaTR@s?^=;Rr5hO2Vaendlx|CE4OcNMvaSq0G zGjjx%ZoSJFe+Jpio znK6{KrAm}Xa|!}nWbYPQj0RX^vs%*TsTcMt$)us0rh&46sF6;MCY-|<#sPSnJQM(x z99HUZ=-^JQd<}J@9P_78$hL7csVYcZ4$Nzs`m?qN~zOg;CoUV!@U*!tK1 z8C%r3vY^ofQRojKw5M2xc@)dLpfJiGEzkwfoX62t zcj1ho&{n@&%X>5~DvWR^LF;j#={geiO)mb0h93Y# zj6cAo`ETgpri_dtDbxFRx;GPo6+o?|rW1PF!MV*y84MzB=s*D&tSC04OgHAK!d;@l z5=6Q#r4?xu704h(B11UpyrhaWmPseT-6`oL_~1f6>PkS@Df@PEfyargjQt?qkg-6l z*g{JGk!m=!Amkk=s%IKVZZ>bJZ(9yU;15EI$Z-U^F8jbvj@UJTLt`=j21Sk`IACgRfl1$fXpxY&xHcB!_@4a@ff2s8NTA=llKr1DgwihOz%e#?q zzn?7BM||*lcr1WrS22`}{-XXCZm}ZRFLR5s0CkzA0gQphJ17@n_JN!X*@r(KpVX5X znjHn=@i#L{DmN0stjRE~l$KW0dOU7a!D3?{78u4D$j=77fQoqBv=mEA#1+djw9yPi zH6Xeq9#5nc(@bg!E1^Qv6vrgLpc9rM)0}o?j zIOrGp9#;p2o@Y{p(6&jSpm8%@wT(!|UoC+2(8%aBLLk4% z(PkGDXEJPti{~>Ioi7Na`BxbH?2r87H?A zyHm>KXj1955A2eRw{)j;=r((y;!JxD_A>Fa#`766tIUthjolmmDCJlOrdET~Ra=2R zP3{c|)A~~qd;;=fEv1dx++^~E&FfPT)bkq9uIC9(0D4|+ksS3oU+il>By4Im{AAH2uRnoef=S*Yx*O#ud8m>77z zBcCDUk8$ZIG0E>Zn4|ps$K){8%@kS4F%*e z4D%T|@fkVv1@Zlp1fO{#4Ab@{!SeA1Ho%l`?jwBQ)^wJu`IHa7GqA>&FZ1QAd?lP8 IUrTrRFBza`F8}}l literal 0 HcmV?d00001 diff --git a/POO/Guia1/tests/test_runner.py b/POO/Guia1/tests/test_runner.py new file mode 100644 index 0000000..8af4329 --- /dev/null +++ b/POO/Guia1/tests/test_runner.py @@ -0,0 +1,92 @@ +from src.services.record_service import RecordService +from src.config.settings import Settings + +import os +import hashlib + + +class TestRunner: + def __init__(self): + base_dir = os.path.dirname(os.path.dirname(__file__)) + self.test_file = os.path.join(base_dir, "data", "records_teste.csv") + self.service = RecordService(self.test_file) + print( + f"\n{calculate_file_hash(os.path.join(base_dir, 'tests', 'test_runner.py'))}" + ) + + def run(self): + print("\n=== EXECUTANDO TESTES ===") + + self.test_load_valid_records() + self.test_invalid_records_ignored() + self.test_search_multiple_terms() + + def test_load_valid_records(self): + print("\n[TESTE 1] Carregamento básico") + + try: + records = self.service.get_all_records() + if len(records) > 0: + print("OK: Registros carregados") + else: + print("FALHA: Nenhum registro carregado") + except Exception as e: + print(f"FALHA: Erro ao carregar registros -> {e}") + + def test_invalid_records_ignored(self): + print("\n[TESTE 2] Validação de registros inválidos") + + try: + records = self.service.get_all_records() + + for r in records: + if r.id <= 0 or not r.name or not r.address: + print("FALHA: Registro inválido não foi filtrado") + return + + print("OK: Registros inválidos ignorados corretamente") + + except Exception as e: + print(f"FALHA: Erro durante validação -> {e}") + + def test_search_multiple_terms(self): + print("\n[TESTE 3] Busca com múltiplos termos") + + try: + self.service.get_all_records() + + results = self.service.search("joao rua a") + + if len(results) == 0: + print("FALHA: Nenhum resultado encontrado") + return + + for r in results: + text = (r.name + " " + r.address).lower() + if "joão" not in text or "rua" not in text or "a" not in text: + print("FALHA: Resultado incorreto na busca") + return + + print("OK: Busca múltiplos termos funcionando") + + except Exception as e: + print(f"FALHA: Erro na busca -> {e}") + + +def calculate_file_hash(file_path): + try: + hash_md5 = hashlib.md5() + + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + + return hash_md5.hexdigest() + + except Exception as e: + print(f"Erro ao calcular hash: {e}") + return None + + +if __name__ == "__main__": + TestRunner().run() diff --git a/POO/Guia2/README.md b/POO/Guia2/README.md new file mode 100644 index 0000000..64f7194 --- /dev/null +++ b/POO/Guia2/README.md @@ -0,0 +1,155 @@ +# Guia 2 — Sistema de Folha de Pagamento (RH) + +## Contexto + +Você faz parte da equipe responsável por manter um módulo de **Folha de Pagamento** dentro de um sistema de **Recursos Humanos (RH)**. + +Esse módulo calcula informações básicas de funcionários de diferentes cargos, como: + +- nome +- matricula +- salario_base + +Atualmente o sistema possui uma hierarquia de classes para representar funcionários, mas carece implementar as subclasses de acordo com o diagrama UML abaixo: + + -------------------------------- + | Funcionario | + -------------------------------- + | - nome | + | - matricula | + | - salario_base | + -------------------------------- + | + dados_basicos() | + | + gerar_contracheque() | + | + calcular_salario_liquido() | + | # calcular_bonus() | + | # calcular_descontos() | + | # calcular_adicionais() | + -------------------------------- + ▲ + ----------------------------------------- + | | | + | | | + ----------------- ----------------- ----------------- + | Desenvolvedor | | Gerente | | Estagiari o | + ----------------- ----------------- ----------------- + | linguagem | | setor | | curso | + | senioridade | | qtd_equipe | | carga_horaria | + ----------------- ----------------- ----------------- + +Seu papel é implementar as subclasses passando nos testes propostos. + +--- + +## 1. Desenvolvedor + +### Atributos adicionais + +- `linguagem` +- `senioridade` + +### Regras + +#### `calcular_bonus()` + +O bônus depende da senioridade: + +| Senioridade | Bônus | +|-------------|----------------------| +| junior | 5% do salário base | +| pleno | 10% do salário base | +| senior | 15% do salário base | + +--- + +#### `calcular_descontos()` + +Desconto fixo de **8% do salário base**. + +--- + +#### `calcular_adicionais()` + +Adicional definido pela linguagem principal: + +| Linguagem | Adicional | +|----------------|-----------| +| Python | +500 | +| Java | +400 | +| JavaScript | +350 | +| Qualquer outra | +200 | + +--- + +## 2. Gerente + +### Atributos adicionais + +- `setor` +- `qtd_equipe` + +### Regras + +#### `calcular_bonus()` + +O bônus depende da quantidade de pessoas na equipe: + +| Tamanho da equipe | Bônus | +|-------------------|---------------------| +| até 5 | 10% do salário base | +| de 6 até 10 | 15% do salário base | +| acima de 10 | 20% do salário base | + +--- + +#### `calcular_descontos()` + +Desconto fixo de **12% do salário base**. + +--- + +#### `calcular_adicionais()` + +Adicional por responsabilidade: + +| Quantidade da equipe | Adicional | +|----------------------|-----------| +| equipe > 10 | +2000 | +| equipe > 5 | +1000 | +| caso contrário | +500 | + +--- + +## 3. Estagiario + +### Atributos adicionais + +- `curso` +- `carga_horaria` + +### Regras + +#### `calcular_bonus()` + +Bônus fixo de **3% do salário base**. + +--- + +#### `calcular_descontos()` + +Desconto fixo de **2% do salário base**. + +--- + +#### `calcular_adicionais()` + +Auxílio baseado na carga horária: + +| Carga horária | Adicional | +|---------------|-----------| +| até 20h | +150 | +| até 30h | +250 | +| acima de 30h | +350 | + +--- +995b5983a8b684cba7bbc7f802c760906f0d690c1e90bf440631cfe486082eb3 \ No newline at end of file diff --git a/POO/Guia2/pytest.ini b/POO/Guia2/pytest.ini new file mode 100644 index 0000000..87b077a --- /dev/null +++ b/POO/Guia2/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +pythonpath = src +testpaths = tests \ No newline at end of file diff --git a/POO/Guia2/requirements.txt b/POO/Guia2/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/POO/Guia2/run_tests.bat b/POO/Guia2/run_tests.bat new file mode 100644 index 0000000..a171223 --- /dev/null +++ b/POO/Guia2/run_tests.bat @@ -0,0 +1,2 @@ +pytest -v +pause \ No newline at end of file diff --git a/POO/Guia2/src/__init__.py b/POO/Guia2/src/__init__.py new file mode 100644 index 0000000..e436592 --- /dev/null +++ b/POO/Guia2/src/__init__.py @@ -0,0 +1 @@ +from folha_pagamento import Estagiario, Gerente, Desenvolvedor, Funcionario diff --git a/POO/Guia2/src/__pycache__/__init__.cpython-312.pyc b/POO/Guia2/src/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..73e61bee553995b8bd027336b80c464892268f93 GIT binary patch literal 274 zcmXwxJx&8L6ol>dhMz>MT!0H~LqP{ZH2kE9AT%^9OO};=BnJPiZ0|}r2@MzEEVNW^ zD5&U=(xu{Af|2HX^Q6(dSJjxHUf0v7TfATS`B(85wnrFVNK0C(iJ=WOMN=5oFjF=q zC7YsV-?>_sX?z``Tq)_5OZzkMU?ZgJ3If={=>b~j)8wYNOXX}X-PNNseRO&)MJHF% zVBdL$TfWQ~W$Yo|$QDU%-+e!o~`3lE*+vtG#)9{iFEp{$BR h9Cw@D!MSm5ui?T^aEYQr4nK@i`bp*=WbO~~{{@WEN-zKb literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/__pycache__/__init__.cpython-314.pyc b/POO/Guia2/src/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d74114fd745841ac03b7505c154fb86f140a25c1 GIT binary patch literal 266 zcmdPqXlRLxg|GpVvh@N>Nl$@Z6K W7sjWHG49bpkM?_X_=fiM7N}opPh`0O literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..693e43684d0c946c77711ea5e834355118268ac2 GIT binary patch literal 350 zcmdPq6uU- zuS;riYF=4>PFZS7ei2Zb-95D^HLoPqPm|*ocN#)x5i`)VTU@Dd%|$FA0p1j3{Y9)G zG4^zb5k+i3-b#kgK$78>y|YzJXmM&$aZGq+Nn%cZjBjaiW^zn`zkiH-X=b8POmR_i zOj>?UMq+$HVtQgO&<*)9@$s2?nI-Y@dIgoYIBatBQ%ZAE?TYw-=7IcHEC?h%Ff%eT V-epj^%b;|ZLE}DyOc4)I6aXfaU#b8A literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4184750c23ee8739353eb22bf091220842d63946 GIT binary patch literal 419 zcmZ8dJx{|h5WP!MDgB6$SXo)Jbbt*Z77*Q97M948WyNj@Byn&)q^_v{p}zs~Q}_cY z5@KLtLu5eegq^ekagv|kv+tgL_w0EC(DAm|yM566yAiu^wxl`KWDOiR#*kou2o_9$ zTPxu9lhtJf*3$8NA4d3C4=>9!jAY7GB*QMDL)?mHq{$it1js?xqHopSg~&x($+!|+ zs;O_+E~P0;1f}(W(nRtyHhe_seaYhP<`EiWxtX4ykn3EioK!3>1kql1h0Ms+Y-Sc! zB9mlNM(l{>DkO6m-!Pi7g|<%%N%-HV$JtW#v}p^5|Lhn8`c&MHQTtST`OnG)6z^N-`DVIBjPI@f4hkNFVN7|`~bVbXleie literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3919e1a349e7a3be0ae81571bd22693621e243a GIT binary patch literal 1967 zcmbtVO>7%Q6nGNUe~N$^}Tu-;FoBw&PTFg~S}*zL|OR-n{R9 z^Y(?ofi&Rw`PU=YFC+kdl9TpOTFU+@RO+w_I(ZAu6HdnAC`^DJ%Yh!hN?wXbc08sh zCLympkkdR7+M9uE+MY{&+cP7RNXA-|{Y6wLP*R7hz=;k#wwmPe5%5S6W{FO6;HW$y z<8VcfqfF`vlzqCw)gs}kBD_X;8e=BKz@o)0cf)fwtg`2u$*y=Z4ZNbdzkteF3|8uF zUQQO_UEE(8D#qJsjKj);+rA>KEW54r0Cd1mWGSBz3JYqMFI2;@U7H(*NIAA!324Qt z3JvdJd%j(!Wh>t&63lYeMZ)!}mPl18_iZz9sOV?Zk-!*hlv#cXZ{*8Dh?HTN4rRb(=D7i55}4@|{t>w}Xi`Vg#W%t|F?P6ihj;t&1Y;=b(9|-!+USlpx^<(Wooo(| ze*8u=o7>G!?PRBJD|fRqclu}Ub!^^mXw%K%u_xL@ejaD@y8`{E{2`3{cwR)!qX#b@ zsdzs2KytM5;qaH|?tk#re4h9@oNtp5Atre@9U(K+$sJj4dPsLBPV_*hV{shMvn&ck zD3jgIOzdPPzF4`NnYp9RJRyS{;fWp@M9jt)fXpU6IUDgTvO@Os@RbPJ7+EQku=;J- z+LFtg{F>+54>5g_c$;oe`<7JGQoU^Yc8%MsxPV}VeMCOuZm6;ysA$;^8?w#BL=UVE zOva>}GhymTl~3nx&TU<3Xj9*3N043NwAj!lyQZavmdEM+>_~_u(z?^u@|x_GF7_qt zm1)DMdgZ{8dcR@37f`3QlQE2S+h-h`DZVJf2pg6!tL8r|#q%h{QEZKza@#a0$8Ne7 za0|Poc&gPnF-2}#j)O}Bt)*y+_sPif?Nw=ruHO_ai4$&`}Y0~BGN;en-mT#P=_e+%me|34p#8oAzv=v4T=)w2;2bN-9C cFX_#OQT!Gsg!~Az57Xl$ck9BRfS>TxzYZtCZU6uP literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..065df0dbcb89a046b855bcc4ae46a3e63fcf4c99 GIT binary patch literal 413 zcmZ8dJx{|h5WP!MDNP$8v9hvc=>Qu-EPQl8qAVmI$Vy;D`PSz&(e~U6RvJcQIN~Y#4IX# zA;`E&*d9?bB2$rGGg`2jE}xfz@ZWbw#a#Au#TE=v1{Uz*xY7)&JvX1*`B!5!{cBj- nn@rg^tThfaTe*i_A4k&H(#%3_YxuAc@fG&JT*Uq-XlOk@grQ}} literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..04075a6534efba7356ad78b087144e07ddd2bb1d GIT binary patch literal 1520 zcmbVM&u<$=6n0f)Q-FB3_cFa@*ViYel4;D7%E2{U7%`EY{8po zZ%?-J0}f4SFGT}<&|Z%E+yETFJmiL5P=-i0e6CDNgD8-cD#J^-h?V6r-evT5%n=2% z$5cW1;hHK$@w%_Z*O}yjmxN4B2o`FbbcG3@k0Tha-$0F1>V-@QO2rs{pG&2uo`2!8 z`vy7+w|z&lFm_)}MBus0H*dPvlYm`x1^3*wIK0j12J5nQKa#QQ538}bafh2aeD$zG ziv#F7k7%I!y$9cz)(2zT=9y1xpP%0`pWd4~`(bIX@#I(L*#mR{k7(T&U7@t9S!c9h zd0-h?9dce*zb{z5+(TW>?%kR9et7NfXIHm~vgl|nwg@kygV34I@sp_436F)kXq>LZ zQ6ki1BP9NAn$S0^sCuwhsqR*0w=1)o?faDr_sk1?63_n!0XRZ{blF_;`Qeoj&}M$H4GedkdjT(ru+xR>X0H^4btfjgqk^yex@ z+}JKRHYaz=b6;0aKd?^iTFq^%xp{HNdIArADnhNEQnzy%1U(^kSK|pFh(|xy@KifuC_M{HOKH1u-S4T=zaTM#>W}yFp?=BbjfMRZF&6iW z#IS!WnnryeP^CQ63peb%nm#hci))8JP_9QO_1uE&RyrT%m8=ra@ddQ&RuuXPf6Nm? TzJ*IamujT`(e$r?OM2@sa^zu! literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a87ac567fc05396055a7991980519217e7f7a3ed GIT binary patch literal 3389 zcmbsrO>Yxd@a>o5&vkHc8=E9{5}+}KfKs?rh|&T@&^A;JJQaZH#6^J zKHq*Hi-ifm!H?tDJ`WP|J5IVFbcpsLAXbS&6hC z<>vzmzrxQ7YCsWGZk|;FEBw>Wve`bD+vnj1Z7vVGK@T?s>%+hc!EOs*(jX zBWvrAz{YHO{cAnDs4HsLP-(WTF34u_raqbDt?);(R#DGUs#8mlY$t`KZ7;9GL_H}AOpRZ1$g%UnK$#7;RqvtQ`Ss1e^xcFoBCq@!%LU&lc>6==g(J) z@>JfSh5Wp(U6rLpc|k6zWmC`3ZwG90amflwQn6e#C8@gC6Uxah7f&@V0=i9piVysp z7}^+~tS63cM34R&AGD{(>xmN^(G#1ISJy^=i0rd@Z`Bj0H=?IElc~G>r{QLL9ENyv zICq!-F_><{Zo~>u)vVBR!3_{Fk+zc}4Fn_wxdx*jX2=s}I>*o`2%az$qh{d3EbRwu zd#&2LBoygu3?+7A~pjsXHE?Hydb@Zdr-HT>1c7bDG~Y-8w1ZRkid znOeQ_;7TKTxRyM;6%zWxEh2=%y>3Jo+HSlJ#0%VrIzH&W09D|F^SUpUN6V*yZNmqy z2E2eX#K~UX?kbj8kTq;=RGQPv6~h{E=dx0?8+*~P5-w9wje-tc#OQJBpsUkOG_81} z0!_5K-|OM$X&r_u8|MIlv!nfu=x{AM+!PZHakM6m*2VEHj*0ExM8?6Ic(5)`Yzb^E z*9wsMKtnuG6A#qI*S7k&*hGulH3C=J0R^1`3VI3!TdNa#!HIa-6X=i|Un}klV=m;`WFKxa)ZK|@ zkjf$&MKp%U*A}hBf=VIFFniz^>8g68qE<(|nb9jh4*M9N0O~0~Z{2yTv5}mpB`501 zL(TL^BRy41Pu0`Mp=ukcW3|+=dTOef8E<4x)-osSnNwSPLRhe&-3k^Cb<%|gVikT6 z?4o(nW0q}tHSM*-&2ZbjXJCCBixzAMMteI0NOn1h;(w^$g|>5d`piAcjoW!#_&TDV z#|@Y-eN+~7tC?NR+D@1EKxzA|>0H822`el~C0(g#(0r|^B;BaUn$wCc4t|dlZc zE2PCng+psIEds-1XZTiVJO<-t^kicF%H1<%y*P_*80m+g?9PI?wR>BQ$0Jpp?7?_^-Lwm61iej($3^A{N=c7OaI If}_3rzZ)*OL;wH) literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4978be748dcb93d2dac0095dda4f16adfba0226 GIT binary patch literal 4983 zcmcgw&2JmW6`$pj6iF>VM2VKfSfV~`M@$^aRg~5#jMRzc#BLhLrE5DtXf0ODm9)ib zSDsx4urJY}KoKB7?Mox|QW!xFI^>TC{11p=5DJ3;agjrjQ)#G=RcW0|2;;?*Z9ybkyc~(BsA8^0x1a>$pyg?E`*#= zf#k?IDTM|}NxUJh;W_Abz#)awR&`-En9@!q8+xL zmaT`|VjZ>^?=j9T3A8wIuIc3(iE9#EljNEd*Yw_yxGv3g8Ps_rNw#c#+?MUIrCPRr zZX4*ZrAs*{bB#ECr6YjjAnSd-YO1rfQaA^OB8+x9uLkLVI6>42%Y{5Ar;Ub zC4UrF0JbZ_yAUESMUcXb2%Uz%3Bh|TY+9=ti?1pU)zzw@Fv(U7{EWP)*c!$Tg2p0C zhNU?06kW0?__CxdtA=9R6uUM(+i#cO zsOrjW*`{iF$ud?Hc}-bXRyEVH%1i##rq^yUNtPAUv>e6JWSI>GCO#dsgyDj} z$sUm+&pkx3d8LWfmRo%m;mTd`A}YSnE{GWXV!Qu<24E&U+p;W6h+4UgE-8_@R(nOb z7J96g5bzQg$muNL-`!Kl_qm=iy)RrJGZ8#quAee-WW1DkjH+pPxC9Xz)6Mtp-!t@z zHC@et?k$Md{ZBDqo<*6ij)CQhV%)z6@f$Pme{7AdSru&zA~I%b%Zj7FXH8!!hFRj8 zVpO&Blv)s4nKK|E`xHpZ9UKU=u&o(OG!DH}%oDU1gpGinfI>6SU@=+NO&z$v20BCL zYI(Tk!Ev2@mG1vCdvtqbx}KfcmS+B)9^#L4_3TUA(n}9|2RFt)?|p{repk<)-ImTi z$PIs(*vU_RnBEyFei6&le(0!U86boR-R>BO?^^~l!X()WQOI$GMXBagsktRkh!vzM znu3ZV;w?V&nbAJfLPW_Cv1;&SN=%Aif_~a1b6U(MaMU0kP@u${z}N@q$Z|FPGcUSclAe@Pa7`p!YJS z`zp#(2=rn9x!o#>pvPUZt6awKb(I-Bw1m6z9E+$5UABsmZhgG91wzV$#! z>`480{`Aqp-GxT(WG#2H8INQVO%jPGd_;eIaOo5b;PA+v1h4&(-8%l5$YNsVk=@|a zJ2#VHYP_DBd?X6VV-HYqqLw;QPfb0Fgp$Q(l%)F`spGZO@p|gnM?GS4swqA# zhTxD6X9!~KGbDj)AH=&9i=4!VkGkAfY~4qe5w_kbPe*;U&1nHc1rSRlvDfTPRCh)cpmfO~O|axC4&tYSRS z$tmpQSM8qYud($T6qsq~%P6{bT9#ebC=eeB4VSeQ?PgVDqd~Inx8oe_H4q2qu8xG& zoyr=ysakHTo_lUb8rnG4$j{dDv-SKOPkoKyQ?=n!_2JnaX=KA`6wcHNXX=GlntgH1 zdGTK~=gs3B2SBtAe@WcjllS0;0o8s+dwV=?J;>-*hS}N&I1dWT2NCwt0T28+=wTN# z-a7eLO!7bVv#0qB@XZ6JeEtciOfi9V(~J|alULrXJ#N2&FLLqI4*c%f_J{3le>iy3 zSD(tHap|$bfuZ&n_nRHFE{g7f7%vDEkAjzqS-zrKLY7ypO4Yz?GF+N(Ru#iNgs`+M zFX_~F4BgaB3r;0?U}v#4YOQJ1xfRF{nDFQ<3Z4sI#a0*v&lEgK@GS@-^gD}c8Dr?5YPr|

T;2=8MV;T)n-e6O z+6%#5YFC6-6I-x{xw?Xlq90#qeB5|r7L`Sn;sM2lhtG-g8kyO;0iSWh@d~{PIt0MRpfyE75WXUl{|*0M O5R!K$za?1n-v19D3zD?} literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..444c7e28d7fdbdb5546407bbd4222630c1e9431c GIT binary patch literal 407 zcmZ8dJx{|h5WP!MHT{T?SXo)Jbbt*Z77$^gEG&^F%ZlALki@}BDs}IF=x;#$6#f8; z#Kgpg$bi%dJ86Z)Nq&CMzI*oFtLF_tM}Kkfu+;m95&Ljas#><@mi%BYdn!*Hsq9GGi*1QJ2sm?nE=zWCH?1)W+U zX~t4PX+5MgmApy}A5;2Nv820shQ^p}Z!XWseIZmqmMkd+xe~==DRXi+otj0J$R!D? zn4OS9MPw$E1*18eYx}H}WZpeG$ychU?OHITFtCO<$5m!T?Ya5c(LaO9?5|a2?=#iF ku(oid+15Spnz&G&mSzgYp@uIT5#QnT$3+}`gNC-|7wB_hPXGV_ literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc b/POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93de29ec64f61d5531c25e94ff020872f6ceedd4 GIT binary patch literal 1787 zcma)7&2QX96o0c`?|Q$wX*S8CG-?_`su)5J1c|Ct-AGgv4y3_|&1JiT<8>B;V<$7? zLvMRQ5DC!>hrp@F_CF{WE}Xa}QmQT%MU}Wv^-!9WuM@oS+R28bly`WZc{A_h_ujnc zmrj)Ofb{pHfscd&@Uz?`q{fTAX|Mfz2`1^lRS?8L3(bsBM!+X^m?H+Mf~$$N^dnS5 zL7p+v$g_qjv^o*FI=oIq9(`uQ>}8wTp0KS<;sw7F00yV+&Ew(%x@q9INAG3o@ByAL z4c3(ez&I?;dr5GxwCKga01QAUWI<1dDi79d7HX6_o+Btlfh~L%=GR4w+UtR{X6xB7 z&24ujOnd&S9p+X|!5k}a&9KN#S7w7Qo7`qOjD*SThdD|u*W{d1p2hvyh&tiLH_kWS z$BVqNbWND9-*_kBj@4Maa;0%OaLiX4oLP+(-~G^}Yi8SAMf`rF-OI!5+BK$0+XHc8 zW|N4e2R?@E&kp>kl{T{5+H;#jH)nRV*Sf=_pXa-yFMLtn!*j5R zVsg^=ZK~(a1GI(!#^jCtTpnC8$c(H?Op{NulYge2)c>^e;Ju#B<&^;eR< zskP@K`mPpBzOOClsb1wuw7;ac2rHl>mw7wO29Sp*EYp>>XLQ;30v?VetxRoKrf#P1RA#n{Gxtj;uhR{BBehd{{^((>X&k5dSb^dh zHi#~cFKe&Ik1wkMhm)j}_U+T3Jbd@|w>6!xVYJCcB!E8LgZubeHn)6ynLHdlf_?w2 zD%C5CRY197^v=M0>A9OQ+PSzgZ>=+KNr@l0`?^bFO2O4&I z`hjdqXA4`!`2`I)PY@X*mC_?fEBi>zmJ`i8hli(*Ks`7dMJs$NioDxbu^%ecxVoF` zJEb$YeVl=zYJ@(1Zqdll3v&8+*zP!e@|3Rnt-zJ*BBkqr>Bc8zN>?1lh3j~>=TjO@ z119s#WB}|mvTztDjxdE|QB&ZMS`LJbLnu5M&m+VmEZcQaREkBtEyh!p`iWFtL{qZg z=jWq`&twNhOb%o&z5VqmR`<7*qE7ARbLz{xBSh8z$Y^SH7m!6bBZUQB2~YiNtj(?* y{7aY|%hAnS(9?=KO}o&`#6|WZp3A4maSp++3L)ek%st7Ek?Ln3{|@+xwEh9{!HAmx literal 0 HcmV?d00001 diff --git a/POO/Guia2/src/folha_pagamento/desenvolvedor.py b/POO/Guia2/src/folha_pagamento/desenvolvedor.py new file mode 100644 index 0000000..c58d949 --- /dev/null +++ b/POO/Guia2/src/folha_pagamento/desenvolvedor.py @@ -0,0 +1,37 @@ +from folha_pagamento.funcionario import Funcionario + +# Desenvolva a classe Desenvolvedor aqui. + + +class Desenvolvedor(Funcionario): + def __init__(self, nome, matricula, salario_base, linguagem, senioridade): + super().__init__(nome, matricula, salario_base) + self.linguagem = linguagem + self.senioridade = senioridade + + def calcular_bonus(self): + if self.senioridade == "junior": + bonus = 5 / 100 + return self._salario_base * bonus + + if self.senioridade == "pleno": + bonus = 10 / 100 + return self._salario_base * bonus + + if self.senioridade == "senior": + bonus = 15 / 100 + return self._salario_base * bonus + + def calcular_descontos(self): + return self._salario_base * (8 / 100) + + def calcular_adicionais(self): + + if self.linguagem == "Python": + return 500 + if self.linguagem == "Java": + return 400 + if self.linguagem == "JavaScript": + return 350 + else: + return 200 diff --git a/POO/Guia2/src/folha_pagamento/estagiario.py b/POO/Guia2/src/folha_pagamento/estagiario.py new file mode 100644 index 0000000..d504cf0 --- /dev/null +++ b/POO/Guia2/src/folha_pagamento/estagiario.py @@ -0,0 +1,26 @@ +from folha_pagamento.funcionario import Funcionario + +# Desenvolva a classe Estagiario aqui. + + +class Estagiario(Funcionario): + def __init__(self, nome, matricula, salario_base, curso, carga_horaria): + super().__init__(nome, matricula, salario_base) + self.curso = curso + self.carga_horaria = carga_horaria + + def calcular_bonus(self): + return self._salario_base * (3 / 100) + + def calcular_descontos(self): + return self._salario_base * 0.02 + + def calcular_adicionais(self): + if self.carga_horaria <= 20: + return 150 + + elif self.carga_horaria <= 30: + return 250 + + else: + return 350 diff --git a/POO/Guia2/src/folha_pagamento/funcionario.py b/POO/Guia2/src/folha_pagamento/funcionario.py new file mode 100644 index 0000000..add2716 --- /dev/null +++ b/POO/Guia2/src/folha_pagamento/funcionario.py @@ -0,0 +1,77 @@ +from abc import ABC, abstractmethod + +class Funcionario(ABC): + def __init__(self, nome: str, matricula: str, salario_base: float): + if not nome: + raise ValueError("Nome inválido.") + + if not matricula: + raise ValueError("Matrícula inválida.") + + if salario_base < 0: + raise ValueError("Salário não pode ser negativo.") + + self._nome = nome + self._matricula = matricula + self._salario_base = salario_base + + # --------------------------- + # Propriedades comuns + # --------------------------- + @property + def nome(self) -> str: + return self._nome + + @property + def matricula(self) -> str: + return self._matricula + + @property + def salario_base(self) -> float: + return self._salario_base + + # --------------------------- + # Métodos concretos + # --------------------------- + def dados_basicos(self) -> dict: + return { + "nome": self.nome, + "matricula": self.matricula, + "salario_base": self.salario_base, + "cargo": self.__class__.__name__ + } + + def calcular_salario_liquido(self) -> float: + return ( + self.salario_base + + self.calcular_bonus() + + self.calcular_adicionais() + - self.calcular_descontos() + ) + + def gerar_contracheque(self) -> dict: + return { + "nome": self.nome, + "matricula": self.matricula, + "cargo": self.__class__.__name__, + "salario_base": self.salario_base, + "bonus": self.calcular_bonus(), + "adicionais": self.calcular_adicionais(), + "descontos": self.calcular_descontos(), + "salario_liquido": self.calcular_salario_liquido() + } + + # --------------------------- + # Contrato abstrato + # --------------------------- + @abstractmethod + def calcular_bonus(self) -> float: + pass + + @abstractmethod + def calcular_descontos(self) -> float: + pass + + @abstractmethod + def calcular_adicionais(self) -> float: + pass \ No newline at end of file diff --git a/POO/Guia2/src/folha_pagamento/gerente.py b/POO/Guia2/src/folha_pagamento/gerente.py new file mode 100644 index 0000000..171e1d9 --- /dev/null +++ b/POO/Guia2/src/folha_pagamento/gerente.py @@ -0,0 +1,34 @@ +from folha_pagamento.funcionario import Funcionario + +# Desenvolva a classe Gerente aqui. + + +class Gerente(Funcionario): + def __init__(self, nome, matricula, salario_base, setor, qtd_equipe): + super().__init__(nome, matricula, salario_base) + self.setor = setor + self.qtd_equipe = qtd_equipe + + def calcular_bonus(self): + + if self.qtd_equipe <= 5: + return self._salario_base * 0.10 + + elif self.qtd_equipe <= 10: + return self._salario_base * 0.15 + + if self.qtd_equipe > 10: + return self._salario_base * 0.20 + + def calcular_descontos(self): + return self._salario_base * 0.12 + + def calcular_adicionais(self): + if self.qtd_equipe > 10: + return 2000 + + elif self.qtd_equipe > 5: + return 1000 + + else: + return 500 diff --git a/POO/Guia2/tests/__init__.py b/POO/Guia2/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/POO/Guia2/tests/__pycache__/__init__.cpython-312.pyc b/POO/Guia2/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65afc7ba052841abcb210e076b4cc2512b3b915a GIT binary patch literal 156 zcmX@j%ge<81i23USs?l`h(HIQS%4zb87dhx8U0o=6fpsLpFwJVSvy_I|p@<2{{|u76W$0`b6Iz^F zR2&mtS(2EOALCnEoS7UG;O`&fUYeO`6jPE~Tv8kpAD@|*SrQ+wS5SG2!zMRBr8Fni Xu80+A0?3YH5aSawBO_xGGmr%Ui*+Gt literal 0 HcmV?d00001 diff --git a/POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc b/POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7c7fd2925e1d12769fbc263f01f8d8d3a56abca GIT binary patch literal 5824 zcmd6rO>7&-6@X`dxTLuH@qeV)apbnHw2>;9lJyg#itJiOilTA?8ASs@D6!(Ml$9wi zJG)dRg#_f*KyxXOo719)pePC(LJOnqAwBm}AcvBcY#9p_b0r~dL%$qkeyPR*|<0oxxSpwygg^tB3jgWt0MU+&i>^=qM4zY+O70HamuJV#n zkR`ID&ZH#Xqs?g0BNx+4nVF14Y;EzFa1>uHCRf%d>C4^%j2f)GoWTZ&n<0 zaMrgy-(xawC6_x;UJcszw9qzijf?VL0Qw&^(%Gt3e}-+ z?G)_Waj9dOmfc^rX~8b}6|-n4h8$>%73^F1#m}+an=oYB0%OAZpP(LSeE7l;D}SCS z;NC=uZryj`soo(~sY>#qk5uIKvi|G2mZiM^ZTT0Ik{aoqfz>DfX1-g$%U_=Ex-C+9oN zB`ZV8$}q2R-=oRO>mEX)TNH|?DtMV~mfiDw*`@i!oud6pcy+iz+|&(F>bi0ForXTVt>Wil*uZO%Y^cNU zkMr7QtZt!k4{v_J21Wz80`Bj=6Acq;(&&*o%s5(zUJI}X+&_C|{F-x*EJDNnQj>sX zlHf~Cwj@TqCPb{MRi&yjE~bE*DM7psB=3|j-r-~sPTc+iv_s}8I4Z$B)yEaGvdE$X zQR7#!CdRzje-k>!Bm+Xkmj98CNQeV$C2{T#u#*pI7tsl3{{P;2M0;SU)|8<~#j{G> znY0q5;I#f7^4i0o`eNaj3X&VGYH#J`Z8*2c{O)ots?>B+z`+h zn}>{Sa4ceOv?h86-JC`7DvE9t=TLkF#aB^$4aIp7f|5Ph08z#sGL9r+_&Nu6$jlry z(3mlt^D#HLr*^R!A&)Uaik0T)ofVgkf*;(t_g4_>L0r602@T>xh^K*u}hhab%6Ce&9PLvfLAO zYAov1!l*OtAC{PD@ir0HFzQTFQowQgIpHXN<4%H(=qidlj|q$T6i^J2Ddx5h?AUaF@D4zSEGXlsye}|?>no|T*$1ev6o}~~VJRv;C__1%! zJo|qv52-QyTSl+K7$lPSTM+Byad!{T3eSF>q2x)&`7kBSHS}CvodCJ14}ntGhwiU5 z^oea1KM%tOUW;Tyoj{tP#b&H-p>d8kKVSo+0bBw1_gA;G?D>9k#It5NLczpm?-ERk#sB8bU+ALTz^219i!y zHv=91HGuyCeCn*(ET3kfBf~JejTF;7wkme_pJl$e}RqpeM{O^hI_q7zr$oId?-Es3 wKFcc7$gU3B4r)(ZW$A|Wg#n{aiFOGFXfU8%maa*=9iZ-THJg$yOKiFS1}LSA7ytkO literal 0 HcmV?d00001 diff --git a/POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc b/POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90b206c77fa6bbde85e7341d5b7846ecad7162aa GIT binary patch literal 6215 zcmds*O>7&-6@X`#%O%CtpMMfdk!(p#Es2#Pn<6F4aa~!lj3_M>6Kk0Afeo>u*7Bwl zmzpJANr3?xEzn#F^w2}oQw}}YJro9-0_nMz9!X2Fj0K9i$DFEIKIPQ+W_N}wiLPuT z28u4o+4pANyxsZx=FN_@x5WrtH~!uE@w`e%9up2E>w~G z$edCR_jx61S%nh$gUDR89PJ}NRntegqsCnioggV+Eyuv-%|;oQ(%oEY+;wG)=&`F( zO7`;faKKNSuAU&}_LuM$0dHEsTQuOULvI0Zox1ckiMM`@kNfbx-r5ikkCf43i!D#=Q4W0wvcrptOrS5kggg3GWQnkgD?C^4Q~W>%m6`I4)q*UPu; zq8lz1%%V-Pk@v|i7P}WNzni`8nAFKGte1^~ot>{ZRz91)dNuog#WKdTWz#7;EX^$i z-*K$8?zZj8p{?K$-^4iqNtHZPNo)7--uOKH`R#jaU!K_1W@^d|#rd%DCN$QvskLM* znWH6>=FMWcVifY&PJU@1uy+3e-nU8?I*Yu7EcB=Sff89DjPeNuaw(J{X(d?d$*Z#i zVuGw*&xEGt2wA;3(+nS(k&G9=}XH-E<^=-fST*!kb<&9gZYXi;-}g+E7E4z&#n z+pw;_hBk+||CemDs0VFU&nTl}6k$F@^oSnKM9xTia--Q}y!QgFKF;$RcNmE%e=B~! zCFv~}q>^$$q8Ysfm-Dys#fxsJw0@Q?1(e1yNntYSMokB%y0K(`+ip0piGAV={TG?(IL`vX&pI1-#`3UmDg}e)7VToiiQO5F$L{oB z^r}q8ow(*|f#v45ItCb9c5cydOt*b+Z8vtQw2n(YXHfS@4hjo7YL;l;UMU&WbX%b~ zw^*?XWvl48YQY8z$L-2Fx9mz`iJ9h>3-+Q>$Q6wh({0H)#!VAFxa~8n(Ux7jLa9yN zW4W6)T`|fzbFEY`ibfeq;w`M_C<4TdHNZe|m|P7X?sZ)vs3e2Rgr|7E&jpq9P78P$ z931Rt7e&ChZ?VR*p39YNnhW$49R>q5a{dBImF%>Vfzd7HzW<{nzS|2CGW4PFBx0=jmbg5~l?4 z^e|gl*oF_a6^zqW*l+$<`zLZ}JH&o-M%_bXptRo7gwsd(xCcBp2>_qN=@@WYg1-!Z z75*V$_7yz_%x+u$OW3FyY` z~O!_eC$7BE!4&k>kuOJO&i(N-T~pkaY(kO z^!k*J*;D#g2__`;x~6YK5&Lanjdz491ca?`@=(#a_K5jESQETFI4&x90@!}pCi1`u z*U-sS;|+v~CxD?B0{0fI;&R1UHdjWCB`Xh`AMBYtLTDZcR}TcjfbS-O@M^Mw#?{%3 z%%FUo2U8-*ZD6T6lw+AN3v%E4zkzZCo`*wO07}Oo_qzwJfIc4=Kd^6%O7o3K)N2yt zsw~J=_XW9;?2E%Q!nY!R_k&yym@LR;QED?-Qsl9F^x$l!7*I2c3Q+2=2ukkU3Xl?A zVVoOtTf~}jj|m7is=P1&quw?!iLX6@i9jJk938|w95)B&1&=5_p7nasvsls?REpQ4 zQ(%t-cK!$ngp{46Z+J`TVL{|*T^p?_vo&pWQyW8Je73I5ZY%z83ya2tDg=a=Z}L!? z<=P|W$SY}D6Ai{2-l1wx6)r&l%Y$*GIGz8NK}m;5vItG`E?ojmM4h@;0=?;J{CfdV zB{LEO)hu5S0#pJ|&pC~^W)uKb+d?7$D)=t)8cwF)#c3SA*96X*%}?WEk?Y|@Z5vR7 z<^LMmEFxJxE-&~6Lev9LMfRP>!z{`R?*ovTLWfIB5iv zCZQdp6+2f3@MJxKSdRyD3$Ms19+4HS)rz%bH#v~A^DRZZxLtx%`>MS#tRfz)@Pzz) zPGK+XIrk1QOznGSj(s1@!50AdT1YQI9UOD#3rMQuasN()-xa(7$`qBZX4Eb zJSB$8wLG;-W$PoBwGp~JGV=A`p#s|KmBn>>36&#mlz%T_VYl0j{R>}M#=Ni@0>3e8 z{+wE6_*x>e+=!pYrh%(^Rosw6^AwNoZUh45a)p{~@Lgrapg(gp_(TIAUCPwjFxkfo z7D%%_hYcph?;osFysaww!xej}QZRo+e*y)_YvzojXk2iD604-JWf!t1flbx)V={l9G3cB8R?-g`~+{4Wu2Ep0>); jHR(Wwb5Du-E>uvVLc1(ok#;*k++pIgSXjCwvDf_%5TZ}O literal 0 HcmV?d00001 diff --git a/POO/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc b/POO/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bdcfb1cf5898e0a23351b53293c72bba75a5ca35 GIT binary patch literal 5706 zcmeHL(Qn(v8NVY>lq}hC;xw6)bg9~=h3U4c?Zio&+Nqtkt2cOQ*I^i77$X>ww&}>C zcBHe|l>lc=u|4)-XkLn;7`DQOfx?gZANDXQa^r%)unxl>i~@yQ@5xX5zB`hpQlmD4 z0O>;s@#FX1{l1UKlkUgg>F*sKSpvuEbmwe7MaX|Jhz^LwvAqVD+r%OkEs+T-uF9NR zR4AEa6DcZtv?M z;UW%;T8gDw%u20>bMQ-|YgYp8HItWIFHp}7o}U)T%Iy&-U!JzhGf>{#JPoZJYp#%O z1ngXX?c(IGJezxy*Uge|Prhz@*L=4!`Sx3H;c0NY;!eIf@0bIVzU}#*um*VHfD4s{ zAiEp#4k(Ia@_qzniTqC^?Z-cu`8f6Q_2ufFcbd78Ive3R=qtug13?>{;z|Dsb9S3l z$t*P7f7GZ#sxsIPNHk9s#e(|jH8ySD%I4r9`LlP_5t;d`_Zq4%xcLT z>03%wo1&JASyRd?3tO3wBNWH1_&r9EyhdZXPP}7@`t7YKjH+Zcd~TjZ9{Mh1nOZDS zbuTQ9s_uhR4v14D9NhW){p2hjY3d_w5x&t{+S06aHSJIlW&9)2+$QE`kCk7|M3tiJ z?}15f&>DqPfm4H1g_G4%3q;RcnZ9%S{V#uU=g+UM&>dxXSf`7%XL>3N=X5XoZs_EP z^XLskP2hx0eY#gDnx*1=$>hdWw>)e!$9#=!N+&LB3}~ zvf~<8P0!BObg}eSv_P#a^r0C*a}Lb~G%p3Lve4hR(`kCJ+p4sRnL zpg$R$O$O(a!OL=JVNOfZpzM-&>mO)|&UyH=&qoKxr5tpM2@v0wG3DHF`3umBT;}}) z%o6z`cWfhfrja{SXJcTSxo5#y#%S&2M*mo&e@w>U_M%${KrbN2HW+^HMJ+OnZG(;d z@uG~HyY4!o&&cMxA~W`v!{)ex9D%qARDi(<7c2CK_l}`)ksnAJzSAE_8YY3v?)A!v zUt|Y(Jv~B_e)q9Y-~9LDpI+si@F2j^Hy@CrE!!))W#4^BJk9Z~#Jka)z=36hu9$w~ zTk%ua|2P_ynOumsC(z5Ic@oW2Xr4xM2FzZp)g@RfDk_Pq53q+3pCGQDMy{vM#=$mo zz2GccVAdu!2FDwN<1z-ffNmWC1wf8(F#Oz$T4Wg81{+7>LP&GhT}O0}Y`!ZpV}IF_ zZfxZUq6#n=;bMis@ZK?0I#5s$*J8eC@@dnUaXISV=S|Bg!g~Z>Kekt~xoNq&rYoC| z!5nOU2nKxof$#z8<9D*TBYci80zN3)aiTYW0}2lCpeYHz0H%n_H9BI=UXV(bR*4by zp|0Iat*W4F)ks5vc4bvXDArUp<$aY#( zrOxY~6i{6eVs{~|FphGVA4P);0@dRAokIzo2x^lbhaRA*j+S*59F18kD(rX%Wh^}- z#>6k-jW42k2F{$3I8erZ;kWosEKR=AHwm4)#R|M>iOLK8spp7~2LLMT$d6bJtx*v@V

6G=KL4lB@x;D`T@x%+8>sj-_ARhySssHVVq3#!sV~P zy5qxWB$tSVA9TkIa$mgz(@0v<$m>|Sl|lFjwvB@EaN&fEAvbf~f-vs8r*XD#hW`Yh zPhrmAz$}r^pLkNx#21}UFO3PVC^T|~IvWDp%=Lj&&-JarHg0Hx;pelkK}NA{upwj$ zL^OBZbp#h=^Iee`CrAg%ufZNIOpDwk=pGvqJfR;6GSLoPNX6iUA@}SBN#&q_3f%r3 zcYN4?$4x;xY!mYxXfh>GJznGtCLl<|R@a~Bwwz_$@^X}q0h=@VwIB!Ef7sCb+*z~* z#fs_U_$Qedm6+_E%+Q=`&6n&;{B7vKf51Hae{xHul>Up5Tjaftf0C118c{NTIDPZ< z*NQ?%>9$Ig!&}1rCach&QnWv(TUkV%x_N4Yb~k8u{lqKZkn|;Go1_)>>%$7YOt+7K NyCvN$qr+k#{|B!WW?TRO literal 0 HcmV?d00001 diff --git a/POO/Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc b/POO/Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7bf0ac9bbd7e3fc5f63135ea786fd3a2fe1fd801 GIT binary patch literal 6102 zcmeHL&2JmW6`x%$m(;Gloy77-B`S7QQFbU%qGUO?63LDcx{zaaflx)knpl%G#g@`i zvt%1NH9(`E#~h0GR^%ubMPTIQKZCRsD_Edtdgwvup-PmKPknE8XSkHuS}|&%4YDBL zyf^dS+u51j-~49Ib$4k5t{?of_s5YSAz3u|1vb0(KY^k~ZV^MePAU>B`FbcBu7rokkJP1pFWy%ef#W3M*%i%Dj+2UR1VMI!|4E;tr!IZxaGjyX zh|zIVO2}@T5%T5iF~X3o*O1PTsJ4p^?>>+m?V4RN3q_L_t(GSYL3;rH`wDYO$#f-eS8OITpm`mPl{Xx%X;K|hVIS<{AZp|* zm2|%H;mSwBkAAxO^GC*(K3`YnX$Q1rMeo7rfj@gP8Dx#5$P!c>yw>}M#cY&igRD<1 zd1LDLT)&!9&hvKx8rF?ea5f3$o$q>X*QCM%A*V@N;c-hU*P7)pG4zx=B^jN|uT9Ab z&lkrz9p+w3>}}+hTQ>W65h@DsMzq|iv(+1|VR+tzHyXT;IT*f{xbFWPcZ1Ep?}^&` zOZ+~D@=RY@_y(Wp8xX$g|M2*Pp7|UKe~xkWyziYThm5e%kqV7VEw$lvADV?+a?4Tt;}uH&TIFg zQO)UYP3d&{T^wz`yn*17F{#s+0oPK7=F2o|t(HxicRHatbGuqBRf=o2qn0f2u$_U7 zy<$~MIp&%vl&srkDYIs-=ADj=ZQjXa2B&+04NTEmyGE%+onx6h7F{(fnf&|ZlDTG9 zpyfe_JG?sH#vRDG<1?oG#*E*%=yuJEX$hKko7}s_CtIw9jrcbb@h*xW;`FcqU<01H zQ+(f|V^E7=YBxaC$mjaYJNns%ezvY8>-yO(eFT(Ew07djMm&kt@#LptOc_fy^yCgS zvEMdEj0jUGzkNffkCi01p0NCfBO%M?SrOnW;QR2TsDmWj!X)u#4}^=WfaAAI0L*Ih z`gRHM0qBcdBLAP3fDc~!_?^Gq{oPx%3tkk4Q508oie!oQqQK>c;(9}mp?C?zyYyv{ zfcf{I6Z3OC3 zsf(DegD(z?A2CN8`ef7dZ01COtAOvrABs9i!YxcP-RyyIaTRc6hqvPh%(h3f~S)iof>HL~2h##@kLwh!b000>SMNq_zV{Z6|#N-jQ}_hFo^W=|B87KkfE0TcDN< z@dU&f&k1q-K1CnKVXB#^4P3RWjPatY!ub)I--&Rh4hSV|I(4%!_ zp{_@_^mC|;FEsRp9mV@?W79cd3I#FFb9t;RaO(+60S(a zi6aO;FGoZ#5!VL2f(*Ta2hdCX8tA2R)Z(RwUa&Q%2?NoqYnM@zc3f;6J~t=KS6~_k z(*>&H-(h{^glzda(TZ=COU3nSF=sWm;{viM;)^pNfa*ZRkKZB@|&xVF;-vd1Qyyr|U$v`RA&|`Jwa$S#Y z=@XzlgnjGf9mV@?W6Ojvg@P#Lxja@bbL$DqSo1c!&PC2dCfEKv;#_%TF^s!@3t zDfRB}L4eM9_nfOEf8Bk`bUF(KooD(kLi_G5ILrh8QLMj$^?gp5pIzv5ACmu0( zc>@X;qxqlFVg*hwM3ocr>evK2svF`2Y?`IW>YNZ96jZ7-?@k*Y7*OQEj4K$>I`iVK;?S(iCZqb>v_Co+^m| literal 0 HcmV?d00001 diff --git a/POO/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc b/POO/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42c8ece72bf1eed6daec55129e5b0f65754100e6 GIT binary patch literal 5809 zcmd6rO>7)V6@aUMre{3uzc`R}5|Xud*Rgw@_%Dus7Hnt5;sAmyECD2AX=qQkz2nTd zXRF(bZDu3~g4pBUvLFr-0+h&?h|_X`11H3Rnb@(TmJlm(01F9u<2~iXdsSWCZD+!m zDAH1ze*LQIy;oK3uCHJD&rMBf0_FSPYgyb*5b}4dhyrz1_8-CR7O{vW<;jf1?s7rN z$`UE4GYN_JXfqo0$oXU;HItHvtu3|%{;`{-+$0-8eI^YyCt{s}x_I)*HcMR~R^pe^ zhRpjcEf%NAO5P+h&HqER6hv!?MN7w`wOBetYh9I$#$6oj>RriCUa_gYAl0CSDn87oFKF%Q$Kd^6q=gzfzgPZ!Lih7Ca(6@H_9nZ?x?=0tv z_W7bsv#{c2GoP7rmX=*ZGvr;I;6Hx;Gc3QGGGy8Sb=m>~`ZVmj$jTp~Zx>%HdW`pB z^uX^=*!LOiLy^UZqJ+=$Yw$?*V(Qq`Ck0a6DEPQ$maGmQ>Q_;qQn(^YTUz-BLVU3oDC_LW}NVtapj~ z*;xGM$UF~yM(Z_)aSM$MZ~PTqRKeQ~<)o!q$x<>Wv0BPIE}lVbE%?$LDy5VdSKNODh+2`#DqM-Own~f??BU1q#DpQO zeZ8xvxH@dO=^qA4$3zEeL!t?kplQHx`?6*}yPP*E-vsG$kC85SOmLSG!)2SxPuVVP z7t?a?s=iWO9Y8UJVi?89<7U%^o$Rr3#tau5#|+(1N88PBbWIo~=Vazg*Y=wa4(q2c z7guqYXH4oJ%Rpxy_dm@#g`!DqzY)4KbIZBBms@guE$@JZ>$hjzx1Hs@#Y{5`d1nsx z@{(Dw{f3Nd&I2im)Ng*BO)cjveThcCvU#b976}LK=|7$p_@?SM%!vXLvA+wX22To z5wP#cuQ>n6A~YN>WeJ!j3C@&dOJek^LB_ILQc5c0V*==z5afGba!+`{cZrZifsDoS!79rsPVg)6JuW#zXl~Eq5&x)%l}GABt;!tN$meRcJdMJLQ28N z|KBSQsShmGYO)kR#H_@gO^x*IsVtR%r7~O^Tnb!jIl;KP@Zs5?{Og+^{(g#Lb^(07 z@r-=6Y&YvHd5#+~wg*Fv0*+s0>jv9=r%t#^#Gg+HVWt8_tQogkfGm(S_n1if$B;O%Q6Jcoju22!YEB z*w6y5G1GV8=kZfa+6f@1t=T;m#0dbJZ?q5KxlaG*p zT~)oSqE3U{)Vo2sGYsNh_s-CCb!eK`LG4Ag0tUTcIlZIeZ(FqRYACDfG{O;0HY0Tl zt-E;hedZbJcZRtdN{cMVg8URyTKYPO+WBc8=kvk*v}Sf%R)E%u zAR`c2Ey;|-kc&bF8nLeyg(aXbW}x5`qpAA|WpYD|6mXV|on$S!4E0)P*|H3@kV9H1kiSWc7Ql_Vw18X> zXn{GO6r)ArQ>I0t4h6z}SjR4;ilsfb6@~d?U0Q^eKnpmd2Itj;m9iR2iGUW`k!hg` zN{D+v3(T*SvI==s`syxjo?JVm9D*C)eMWAG>?oguf9zOJlwQT*!47dxp+$R0i$kG~ zjEp2l2BsuWrv>hrfEMxN-=Q&s!(V2MeiiI7-Ew~oVx2rZd5RtWK5FR>PJF#py|+s(JIPZHjw`Q~BGRq7pB9=Wqil;a>EB3@6r@l~dtmV8tNv}Z% zCQ$BsAodhVlKw`>P4eTWzmgaBG$N;ddiKWIk7ZdJ*;k0%x`*0c8rx6bIK3maSEcsK y$&p7SIWF&$q^x}0sz?L-$3WXd?NOsFU6Gz}7z2mT3kO-63LH>NtI}(1rvCvcfpkFt literal 0 HcmV?d00001 diff --git a/POO/Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc b/POO/Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5f85b90d8e67727a2bc8bfe270e203a1cfddf5b GIT binary patch literal 6195 zcmds*OK{u98Gsic_z zmOGxIr>`7)YSzZj3b6S6{}k#B?-BUYrF{3MjTz)S4^DP-=-Jm|};u!m>dv-40Am&#W@btDjx9x8`vu zD&%E|G#~rj%DGGG<)`3@_L?urq$DR zJ+*Q>@7zn0BUp>JW#0UrMq z$1MC{%%KrwNIXTD4`D5=MUvqWX-{h;b&TIL->ARG+q^T}(FngPe!eGZO_!yja#^BD ztqGUzH}dSP9Vo7kvh{${I2Lg%Chdq}!i3jX3g5KqCag89r*ELRJ{>brJq;_Kwm^q5 z>A_8GkH^gDFI=H#mYI(8CJ@}F(U>`$(Q}z{PN&Wqias2OMIZLeIxdqjGp5>6Z_U}w zrVh5*LV8&@4ZC%(vmL!!T*sxJ)~Vf*24yZyjUvqy)`~hc>}F7>m&@6lmCc)WC|3Xr z)9y-}_X_3Q3NuZw<_gQOp!52gVK=2s{Vw35NbS~l*qF10{B=qT)IOHJTcB&Yl{W4d zb9!F4Koe_XH;y8q?e=;)P=vd!;w3ouZ_Hnr@K-K66{m+Oe`Ur*3ibE*_ppQFinUL( zAu|M}iv^mt^ff(yui#>e;xt4WnSX(zLUuaI$@81a8!y_rx6V%1&Q5;bHd$GGp>}Sm zy*0JBs*F_C-VOB}2#@dA)R8U4{cWP=oTv)n!zm#?Q$~30Ig8_H8hV1k^mc&J!A%2YfTM!-NB!`FLHyV?*Lv$f!7lJW%!5S9{_e= z*P_7gmeo(r{QBQN{N&Rs6d%09AzUOB_e&)76vchPR*LImqYv7A1Rt9Kgk$r>`xMd# zB>1D(B>0M9W(s+$V0siEz)({F{2#DAU<`=w>px`t2A9fX^gJ4~y}}{z*!Z4W z++nao;GQ0b!JUl3{7Tbzv-b;h9OB@`nl&gYUrp_+D)UvfZ$rHR!jm`@TjTS! z@p)_>pZ|Q234`-Bb$$y}?6-*?7erME2wT_WnKI97&sqHao)G0pTsSxa*go|FLl9oW zAmiQ@)VYD7lMkQv_U0jdC7Xe55OzhtH~X87JyX}l8&zXsWEh-JH>x@H`{fH$+BIRt~R12#cu4*{j-^3w#_gqNU6OhDS7a$50w}S6W*wkKpqqP z^Nf$ozKEBJQv7;A1qB)1XdkxqLt)~K;Q6G3vR)^H7K^z-N;wHmNL%wyQ20_xBwT+@ z?XN0xRkeRZ9YA4duBOgyDei9*RRf|b1caAs@=TfIwdX95qiN`g218zSaP?P3ND#ns ze;z5`(tpF4bSIJ|c^Hy&Xwjl{0GZDE$TX3Z7@4l|6>wxSsYwOM)VwtIogtH0)knw| zJ&JuhWD>b6e=bKPlkjUmrXV9zu#QZjS0Gb}6N#T)GC@v9dcnn{x(tbmZ%B= zDdd_wQ)YPWIg8_H8hV1k(=NZKuO^y706RvcSSTiMM$z4GjG3yGA7em)Lci6Oy{uuU(hGWSFwHG zX@~b*vR#GS55Da6VFBAa>FBZ){FxZz1mPJ$CaM)9(Y;E925NETB zyuDUfDd&tiszDnL*ZdHQoq!}s|0LvB Date: Fri, 22 May 2026 23:20:42 -0300 Subject: [PATCH 02/12] Delete Guia1 directory --- Guia1/README.md | 202 ------------------ Guia1/data/records.csv | 6 - Guia1/data/records_teste.csv | 8 - Guia1/src/__init__.py | 0 .../src/__pycache__/__init__.cpython-312.pyc | Bin 154 -> 0 bytes Guia1/src/__pycache__/main.cpython-312.pyc | Bin 1354 -> 0 bytes Guia1/src/config/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 161 -> 0 bytes .../__pycache__/settings.cpython-312.pyc | Bin 702 -> 0 bytes Guia1/src/config/settings.py | 5 - Guia1/src/main.py | 31 --- Guia1/src/models/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 161 -> 0 bytes .../models/__pycache__/record.cpython-312.pyc | Bin 1395 -> 0 bytes Guia1/src/models/record.py | 20 -- Guia1/src/repositories/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 167 -> 0 bytes .../abstract_repository.cpython-312.pyc | Bin 758 -> 0 bytes .../record_repository.cpython-312.pyc | Bin 1711 -> 0 bytes Guia1/src/repositories/abstract_repository.py | 11 - Guia1/src/repositories/record_repository.py | 24 --- Guia1/src/services/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 163 -> 0 bytes .../record_service.cpython-312.pyc | Bin 1228 -> 0 bytes Guia1/src/services/record_service.py | 14 -- Guia1/src/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 160 -> 0 bytes .../__pycache__/file_loader.cpython-312.pyc | Bin 1137 -> 0 bytes Guia1/src/utils/file_loader.py | 14 -- Guia1/tests/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 156 -> 0 bytes .../__pycache__/test_runner.cpython-312.pyc | Bin 5184 -> 0 bytes Guia1/tests/test_runner.py | 88 -------- 33 files changed, 423 deletions(-) delete mode 100644 Guia1/README.md delete mode 100644 Guia1/data/records.csv delete mode 100644 Guia1/data/records_teste.csv delete mode 100644 Guia1/src/__init__.py delete mode 100644 Guia1/src/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/src/__pycache__/main.cpython-312.pyc delete mode 100644 Guia1/src/config/__init__.py delete mode 100644 Guia1/src/config/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/src/config/__pycache__/settings.cpython-312.pyc delete mode 100644 Guia1/src/config/settings.py delete mode 100644 Guia1/src/main.py delete mode 100644 Guia1/src/models/__init__.py delete mode 100644 Guia1/src/models/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/src/models/__pycache__/record.cpython-312.pyc delete mode 100644 Guia1/src/models/record.py delete mode 100644 Guia1/src/repositories/__init__.py delete mode 100644 Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc delete mode 100644 Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc delete mode 100644 Guia1/src/repositories/abstract_repository.py delete mode 100644 Guia1/src/repositories/record_repository.py delete mode 100644 Guia1/src/services/__init__.py delete mode 100644 Guia1/src/services/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/src/services/__pycache__/record_service.cpython-312.pyc delete mode 100644 Guia1/src/services/record_service.py delete mode 100644 Guia1/src/utils/__init__.py delete mode 100644 Guia1/src/utils/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc delete mode 100644 Guia1/src/utils/file_loader.py delete mode 100644 Guia1/tests/__init__.py delete mode 100644 Guia1/tests/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia1/tests/__pycache__/test_runner.cpython-312.pyc delete mode 100644 Guia1/tests/test_runner.py diff --git a/Guia1/README.md b/Guia1/README.md deleted file mode 100644 index 8bdcc3b..0000000 --- a/Guia1/README.md +++ /dev/null @@ -1,202 +0,0 @@ -# Guia 1 - Carregando Dados - - -Este projeto tem como objetivo praticar conceitos de Programação Orientada a Objetos (POO) em Python, utilizando uma aplicação simples baseada em leitura de arquivos, criação de objetos e processamento em memória. - ---- - -## 🎯 Objetivo - -Você deve analisar o código existente e implementar melhorias para que o sistema: - -- Valide corretamente os dados carregados do arquivo -- Permita buscas mais avançadas -- Passe em todos os testes automatizados - ---- - -## ▶️ Como executar - -### Executar aplicação - - -python -m src.main - - -### Executar testes - - -python -m tests.test_runner - - ---- - -## ✅ Critério de sucesso - -Ao executar os testes, o resultado esperado é: - -- Todos os testes com status **OK** -- Nenhuma mensagem contendo **FALHA** - -Se houver qualquer **FALHA**, o sistema ainda está incorreto. - ---- - -## 🧩 ISSUE 1 — Validação de Dados - -### Problema - -O sistema atualmente carrega dados do arquivo sem validação. - -Isso permite registros inválidos, como: -- ID vazio ou negativo -- Nome vazio -- Endereço vazio - ---- - -### Sua tarefa - -Implementar validação para garantir que: - -- `id` seja inteiro positivo -- `name` não seja vazio -- `address` não seja vazio - ---- - -### Regras - -- Registros inválidos devem ser ignorados -- O sistema deve continuar funcionando normalmente -- Deve ser exibida mensagem indicando o erro - ---- - -### Exemplo esperado - - -Registro inválido ignorado: {'id': '', 'name': 'Sem ID', 'address': 'Rua C'} - - ---- - -### Onde implementar - -- `models/record.py` -ou -- `repositories/record_repository.py` - ---- - -## 🧩 ISSUE 2 — Busca com Múltiplos Termos - -### Problema - -A busca atual aceita apenas um termo simples. - ---- - -### Sua tarefa - -Permitir que o usuário informe múltiplos termos: - - -joao rua a - - ---- - -### Regras - -- Separar a entrada em palavras -- A busca deve ser: - - Case-insensitive - - Aplicada em `name` e `address` -- O registro só deve ser retornado se contiver **todos os termos** - ---- - -### Exemplo esperado - -Entrada: - -joao rua a - - -Saída: - -Record(id=1, name='João Silva', address='Rua A 123') - - ---- - -### Onde implementar - -- `services/record_service.py` -ou -- `repositories/record_repository.py` - ---- - -## 🧪 Sobre os testes - -O arquivo: - - -tests/test_runner.py - - -executa automaticamente: - -- Carregamento de dados -- Validação de registros inválidos -- Busca com múltiplos termos - ---- - -## ⚠️ Importante - -- Não altere os testes -- Corrija apenas o código da aplicação -- O objetivo é fazer o sistema passar nos testes corretamente - ---- - -## 💡 Dica - -Se você precisar escolher onde implementar a lógica: - -- **Validação → Model ou Repository** -- **Regra de busca → Service ou Repository** - -Essa decisão faz parte da avaliação. - ---- - -## 🚀 Resultado esperado - -Ao final, o sistema deve: - -- Carregar apenas dados válidos -- Permitir buscas avançadas -- Executar todos os testes sem falhas - - -OK: Registros carregados -OK: Registros inválidos ignorados corretamente -OK: Busca múltiplos termos funcionando - - ---- - -## 📌 Conclusão - -Se passou nos testes sem falhas: - -✔ Você implementou corretamente -✔ Você entendeu a separação de responsabilidades -✔ Você aplicou POO de forma prática - -Caso contrário: revise sua modelagem. ->>77f39f6cb45e487337a25f811b074ceb<< \ No newline at end of file diff --git a/Guia1/data/records.csv b/Guia1/data/records.csv deleted file mode 100644 index a672050..0000000 --- a/Guia1/data/records.csv +++ /dev/null @@ -1,6 +0,0 @@ -id,name,address -1,João Silva,Rua A 123 -2,Maria Souza,Rua B 456 -3,Carlos Lima,Rua C 789 -4,Ana Paula,Rua A 999 -5,João Pedro,Rua D 321 \ No newline at end of file diff --git a/Guia1/data/records_teste.csv b/Guia1/data/records_teste.csv deleted file mode 100644 index 5a3020e..0000000 --- a/Guia1/data/records_teste.csv +++ /dev/null @@ -1,8 +0,0 @@ -id,name,address -1,João Silva,Rua A 123 -2,Maria Souza,Rua B 456 -,Sem ID,Rua C 000 -4,,Rua D 111 -5,Carlos Lima, --1,ID Negativo,Rua X -6,Ana Paula,Rua A 999s \ No newline at end of file diff --git a/Guia1/src/__init__.py b/Guia1/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia1/src/__pycache__/__init__.cpython-312.pyc b/Guia1/src/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 508044149c0e1da12c8d749bf240946e280aa495..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154 zcmX@j%ge<81RulLvq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!vUIkJ2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=3nE3e2yv&mLc)fzkUmP~M`6;D2 Zsdh!IK$94OxERFv$jr#dSi}ru0RTanB}V`N diff --git a/Guia1/src/__pycache__/main.cpython-312.pyc b/Guia1/src/__pycache__/main.cpython-312.pyc deleted file mode 100644 index 6f428612b362df54b091ea986c3d9b5eafc200da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1354 zcmb_c&2Jl35TEC_yIwo~Xf{M`Y9AITC>CN1g7i=|Ab+H3C6qwi9vZn?S>A`csl997 zuA4ftQ4S#a0FpVN9sr3G2=&T8KzihoG=Zcm_XHPiCJ9oNTzGHom2>05NINrc<~JYj z&1ip($D_aqe-vK(Cj{^ZKLo_iJ{?_S;t?2Npc>TCDneWj)k1Z=ikXf-gH?fuhH!rt zfXX2t!sAgWf|l44GtyuDoIzfEg;Z>66bXG`RtPi5MdG@qRdp((2w#YdWA+{WjCf_2 z@gccEPp~Egwy}IX!gat62UY_GRs<1f!&)TpjAhVm2enZF?#2N+p>c+GXq@4Tq`sW#CKpF{a<-9($YqHeturfXIEAh7PCu*WtGXB#ak=O zMU^==qyC9A~M%e9(L{T+0?$il-4 zX}G3sd7^1Gnyx1~q)aRKGLjc|hAZlY12m!@BA(z9TIWWmS#upnVx?4{PUiAgOSf5+ zQ+iOYxujGe&VAQzls;Tu<{zutuuF?gv;20+p_Nj-Y+72QJ_WOkJ|y5WP#3x|Lr)7@-8Hradm z%Nu`Vb~=uM7~PJh_JnkQ;@tM+o4XU*W?>-6Vw#0N(!SEZe`!~Fy&HZup&U%7S%&yb z5B1MY_sU<(EJJ+eSc15+tz7;s_STEz6vU?-;=`)CZIkh9FP6wEoPnTJ8#LNfVqak=#3YE0xG;cuNzxekGDW zkGI}WP|NE|4WCMwxhGeV3< zr=!?$*e8g^W$Y=8DNL)GAu>^%mCTwfw>W}ROG+~H(u;4gq$HLkR&f`lCg&HW6ze4y zm-%UO-QtLk&r8frjgP;@6(66QpHi9wV)Mku7nUaGKxLTnfw~J4OEPY;r(_m^1VP%; zGQmnYoE(E)<6S(1Zn0$LXXf4Fba4!EjCb?&ab3yq8RV2-4$f9Fp~b01#W7`xIVGtv zE~&-YCHVz00sj6V9AA`LkRRh-nwe-AQ(TlBlboNImYE(?40X3&L1hsr+Q9_KZ^bS^ zqJ`lGzhHlPXL)~pXZ?(#`QOwIIAQD}0T2r;B?M&s;;?~)id~T~kPC{Y aVvzU;W=2NF+YFrFS(q5@J~03ZupR&?zLd`Z diff --git a/Guia1/src/config/settings.py b/Guia1/src/config/settings.py deleted file mode 100644 index 254197a..0000000 --- a/Guia1/src/config/settings.py +++ /dev/null @@ -1,5 +0,0 @@ -import os - -class Settings: - BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) - DATA_FILE = os.path.join(BASE_DIR, "data", "records.csv") \ No newline at end of file diff --git a/Guia1/src/main.py b/Guia1/src/main.py deleted file mode 100644 index d460e33..0000000 --- a/Guia1/src/main.py +++ /dev/null @@ -1,31 +0,0 @@ -from src.services.record_service import RecordService -from src.config.settings import Settings - -def main(): - service = RecordService(Settings.DATA_FILE) - - print("=== CARREGANDO REGISTROS ===") - try: - records = service.get_all_records() - for r in records: - print(r) - except Exception as e: - print(f"Erro: {e}") - return - - print("\n=== BUSCA ===") - term = input("Digite nome ou endereço: ") - - try: - results = service.search(term) - if results: - for r in results: - print(r) - else: - print("Nenhum registro encontrado.") - except Exception as e: - print(f"Erro: {e}") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/Guia1/src/models/__init__.py b/Guia1/src/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia1/src/models/__pycache__/__init__.cpython-312.pyc b/Guia1/src/models/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index f2285cc1d7873a863d22504288650b51d1c3561a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161 zcmX@j%ge<81RulLvq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!a&Wea2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=3nB4r7)STj&`1s7c%#!$cy@JYL e95z6~(wtPgB37V*j6hrrVtiy~WMnL22C@K)&L}Pb diff --git a/Guia1/src/models/__pycache__/record.cpython-312.pyc b/Guia1/src/models/__pycache__/record.cpython-312.pyc deleted file mode 100644 index 42aff45eed484b119ac8efadfd58c87324087051..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1395 zcmbtT%}*0S6rb6zZVRPiV*~_g;sI+2iSb5+i$pj95e3q0oHU&!+1k=NQw-fe!l4I9 zG#lh7 zwqkItre$>7;ChW5h8Hpsh>dfx3323H9OY(>WMb85I_4SA>|9B3FDiV?9PVkW*`n=5 zvYZQB%3Qm5td8BP@U+H2?UD_;K^S;}Y$y=HKa;lROshjnl(6gUAs=8;jC1WvS1kp+_0XWdxP z+TO(V<=baDfo+)yVs)H0~POao{{orPb+N56|LAl3bj fPR+-`jFVy*a(-LA;51cA>0c#Dm+2pZ+Q0G-QeG8< diff --git a/Guia1/src/models/record.py b/Guia1/src/models/record.py deleted file mode 100644 index 5c5bc4c..0000000 --- a/Guia1/src/models/record.py +++ /dev/null @@ -1,20 +0,0 @@ -class Record: - def __init__(self, record_id: int, name: str, address: str): - self._id = record_id - self._name = name - self._address = address - - @property - def id(self): - return self._id - - @property - def name(self): - return self._name - - @property - def address(self): - return self._address - - def __repr__(self): - return f"Record(id={self._id}, name='{self._name}', address='{self._address}')" \ No newline at end of file diff --git a/Guia1/src/repositories/__init__.py b/Guia1/src/repositories/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc b/Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 219943d13c57a83f70ca1d7d47146793bb279d63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167 zcmX@j%ge<81fRm#vq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!a&xwd2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=37!bEOvn0PLGqpG-K0Y%qvm`!V jub}c5hfQvNN@-52T@fqLSVkZ&1~EP|Gcqz3F#}lu!7VD; diff --git a/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc b/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc deleted file mode 100644 index 75a73ffdf35f2cab02f70cce6448b7c0973e8b06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 758 zcmZuuv2N5r5S`t%FD9IWLLwnVa}t#)f`AU8NFhk+E&++gvb1u%8|A>p$F2|QQc>JL zTz(-+#c#kLY(pd}x&uR#iW&Qi62VG-`^Gc--t5koFkA&(pAJ^ue8&A71>N$Oq<(;8 z4hj^@pRiQxJ146q~{MvNHBC=Gs5vO3b{!e|zNQZtpDBU+HmaM^$O28M|tMoLp)T zVGdI`W5Y9unDea8k1UlAE?@3GOy=9_iu+=U6Nk7Cin;!LBB=<&a1R3GEV%;x^@Q> zV8+})h`6EonOg{!&I|_TCT^~0b!xKXle_VeFP_Ps%D+SMu|ikYtth}Kt0=s2s60wH-2#DhqZv-=7QLw*Rj(l zKcP!CMNLDE!Z7ljNDnhZQmuERe%_zk!< G+J6AH@2pP% diff --git a/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc b/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc deleted file mode 100644 index f76d38a1756ade4d7422d23b0b37569b6c91650a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1711 zcmaJ>&1)N15TCdER+3fAQX&^ewi~N)+Onk>f^%wvjg!z&D0WE6MW`%W?K+XWvYhwU zGB#4l!3T$?I3@+;NdJwW3NKT!3E2&CqGO+XJKo|`yWn4Q7s|5em&Gz#BiGzQSvV-gKQDUjmu1^= zMInq2ITokr@MB!+;6jc$kkcII>a&`ot@0dq^i{|i4p$ZfE$YWXD$M=g|AL-b{D-w* z`!@^iw3M4J z&Ayts^lARObcM`UY|nS|mtFa-UtY*xotdEzV;9Q#D~m<@TwaPoo>X-^MOUIim!r0X zH#WAgjK8yr^F`mXRx)oMaIEc$QUNJsw_$&9bdBFl?w=Z5<3A)0(FTRiaZu^OPaXa@ z6zbr2d~@Abgg&Aw%<)j_=3A|p8mqF)u&x!f8&J@`ejlKw`BaJ`pZ=t%is)rfYR93j zk&dgb?5zgc(C&_M%v945f_76<4XSm+Ty6dp?qh225}15C(27pL=k1akL~X|ru9Rj( zP>vwxVUt+}SrPA`D(F0cUYz$uFG{8^5@g_x?c0Ga%1e@p$!4>nkL+Qv?Rm#szRHU( zN-OioZo{)==8xo=z2uqA^S?|!oP3fTU*nAkoEm;%=$ZKQRQgDVMEb|^d-B2gjph3j zo8z06ho5ch+h6STJ?))r>bMKhOEhAT>R+$jsqMywUp9NtD(Ngge>ioT2i$i>>9vNA zpig1Civl(DTnAM&v}mifB5H6P)?G+mAS7`twByi!TkZa~s93tdme_fMwLbMIEYvQep5H>&r)+e?1%Yyb9%$C;hXHL3==dK;xw{HAZV^tHwv09#i$wN2(ndZaLpLn96bbFnz4xSUL$1~@dx8afJ+!l zVN}9dd~n9PADl6}^+tC+If5D~I6+&nO4pMZL9bFcIPa2u(J!J|J%}^|2ny8`RyRsg sr{Y(!3*k{G#7F3$u9QQ_8aiX_04^QC*#r3Gh^JY6cfkAya8<$o0!#yaTmS$7 diff --git a/Guia1/src/repositories/abstract_repository.py b/Guia1/src/repositories/abstract_repository.py deleted file mode 100644 index 681b898..0000000 --- a/Guia1/src/repositories/abstract_repository.py +++ /dev/null @@ -1,11 +0,0 @@ -from abc import ABC, abstractmethod - -class AbstractRepository(ABC): - - @abstractmethod - def load_all(self): - pass - - @abstractmethod - def search(self, term: str): - pass \ No newline at end of file diff --git a/Guia1/src/repositories/record_repository.py b/Guia1/src/repositories/record_repository.py deleted file mode 100644 index bded279..0000000 --- a/Guia1/src/repositories/record_repository.py +++ /dev/null @@ -1,24 +0,0 @@ -from src.repositories.abstract_repository import AbstractRepository -from src.models.record import Record -from src.utils.file_loader import FileLoader - -class RecordRepository(AbstractRepository): - - def __init__(self, file_path: str): - self._file_path = file_path - self._records = [] - - def load_all(self): - data = FileLoader.load_csv(self._file_path) - self._records = [ - Record(int(row["id"]), row["name"], row["address"]) - for row in data - ] - return self._records - - def search(self, term: str): - term = term.lower() - return [ - r for r in self._records - if term in r.name.lower() or term in r.address.lower() - ] \ No newline at end of file diff --git a/Guia1/src/services/__init__.py b/Guia1/src/services/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia1/src/services/__pycache__/__init__.cpython-312.pyc b/Guia1/src/services/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 7156b3400d03c95edf785d73c6374451cf8d4037..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmX@j%ge<81RulLvq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!a&oqc2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=37@*3s%;ePKnE3e2yv&mLc)fzk hUmP~M`6;D2sdh!IKqDD}xERFv$jr#dSi}ru0RZsEDG&ev diff --git a/Guia1/src/services/__pycache__/record_service.cpython-312.pyc b/Guia1/src/services/__pycache__/record_service.cpython-312.pyc deleted file mode 100644 index 29288bfcc275c671ade748d6ba8a812eb45dfc94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1228 zcmZuw%}*0i5TCanrBIqhFhGKYMh#*4N{kVRF?vvgUJ3#A&@|bs-G^-1vh}?!u}u%e zaPX+{P>*<%@K2a{^ipgLy1|nt17rbv}%S%8QU$6Ts$_hPgrwEap98Ic+O1O>l>fm zJGSNOim!5y*+swWiRqN+ea2iCf*9k}WVuzuR6xisAd8wP0Fw2iqH^&pc%h5HncqOR z3E#E8*Iupirt-GB&Atri2fdf-!?TUvxqA29DLhB_w9##^p-tA~lL4Y>oEB`bb+bSX z!|yVTf@_sW>zW_uFf diff --git a/Guia1/src/services/record_service.py b/Guia1/src/services/record_service.py deleted file mode 100644 index 0317c85..0000000 --- a/Guia1/src/services/record_service.py +++ /dev/null @@ -1,14 +0,0 @@ -from src.repositories.record_repository import RecordRepository - -class RecordService: - - def __init__(self, file_path: str): - self._repository = RecordRepository(file_path) - - def get_all_records(self): - return self._repository.load_all() - - def search(self, term: str): - if not term or term.strip() == "": - raise ValueError("Termo de busca inválido") - return self._repository.search(term) \ No newline at end of file diff --git a/Guia1/src/utils/__init__.py b/Guia1/src/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia1/src/utils/__pycache__/__init__.cpython-312.pyc b/Guia1/src/utils/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 2548ac61dcece040fdeac36e6b7cef944bbde22c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160 zcmX@j%ge<81fRm#vq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!vUj$M2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|nBt=3n9`EWoZ^`H_{_Y_lK6PNg34bU fHo5sJr8%i~MXW&c7=gGL#Q4a}$jDg43}gWSU`;36 diff --git a/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc b/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc deleted file mode 100644 index 6b5ca6a21d9cb8e3b88c17bad2a4a743ae0d4df1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1137 zcmY*Y&1(};5TCbiH($2eMvK;lx@tY-(4vSaB?fB0E>cDD&=6Rb-B-Ic&BnJct*xm@ z^$#d`s3M}^MX85^9>j|lFM^jqJ*_zip1jpWD6|*nZL&pY+2790Z)V=So%g=Bw(%JY7Xt888lk8yrJNvpr4F<~`bO{6WOaRQZ9 zV2~p=bktYf5-a-D^5*=+h+~OsESQX1a6I96%2`dg zV$3ZUZCL?FHhRZmCE>W3Wyd^|_qdfW3#Z`agL6>`4#_}i!H-GRz#bP5%8r_+XCQRS z2D}Fd_hCzo#GqVLsd*3Iu)}4CZ`=s}ky4l^o5~&^Tc|7*0vaKPv zEd%NjcK<}6<9HoNe3aCZJ=Nax@8j!ttEu75DF>RhOg=5V!G40yC16Sf*2(O`m2>g%)`QHPO zm%{5ocnCkV&MhUTWgidM0Y422k>qdb;F1rb(+Za-xtV@cY5^rn?!+?9ezH7;ro2pE U5&<_%$ahF=tNTc{4hTWcU*u5>S^xk5 diff --git a/Guia1/src/utils/file_loader.py b/Guia1/src/utils/file_loader.py deleted file mode 100644 index c9afe65..0000000 --- a/Guia1/src/utils/file_loader.py +++ /dev/null @@ -1,14 +0,0 @@ -import csv - -class FileLoader: - - @staticmethod - def load_csv(file_path: str): - try: - with open(file_path, mode='r', encoding='utf-8') as file: - reader = csv.DictReader(file) - return list(reader) - except FileNotFoundError: - raise Exception(f"Arquivo não encontrado: {file_path}") - except Exception as e: - raise Exception(f"Erro ao ler arquivo: {str(e)}") \ No newline at end of file diff --git a/Guia1/tests/__init__.py b/Guia1/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia1/tests/__pycache__/__init__.cpython-312.pyc b/Guia1/tests/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index d4029fa49e430451318e97857bdcbdee513b4004..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmX@j%ge<81Yg70vq1D?5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!vUawL2`x@7Dvl{j z%qdBYaY-%CF3B&53Gnv^;rOD|g8Ufw(#%A|n3B}ulH!>7_{_Y_lK6PNg34bUHo5sJ br8%i~MXW%x7=gGL#Q4a}$jDg43}gWSq{k*W diff --git a/Guia1/tests/__pycache__/test_runner.cpython-312.pyc b/Guia1/tests/__pycache__/test_runner.cpython-312.pyc deleted file mode 100644 index 5cc7ad8300e869efaa348ebcb42884e54da251ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5184 zcmb_gTWl2989uW!sH(6_Bva7`q*f};o5M@1zU*dg*_k?0)bP?b$Bq=_y!1b3F1rS& zm#Aa!xu5_1bI$*L|9|Fhfq);u^XK#4(I-&)j8vS5vkPlEC`=&*DNG8DF#`-k%AS;G zj2&QUnN4v69JH}1et`F&lStvNB89*2u_O#sC>2-HfL9e1@5Q|c;TjK8EAHFkN5giZ zEOYu8G|5h~QQ@DYFUpvKSJZ@tm9r|oluW45Ae>bVBbgr7`x0f-5o1@@_Ca9^sc3*v z(11r_Kn+&$K*}jBq&!g+)Z-!bPF6&{roUg+jaM@1w2Bjs6e5gl6AQn!acG@F25Foo#dl@dCe++gBcZ$l>4?OPW~42AEf!5nWa3(D2(E{Pu>BZ9E!U-8Ud?~w2o49 zaOzg>tO|3yPLHwGDJiVs9^g09iUUKjwQ^SaHTsRmDT4{1XhomNDY7AFw_<7ldfb3x zQkxU{rFF({@}#C`gCvV%dU(y_lTp9v(R7m=myHqAt0Zw+9#c&r9v@1k)Og(FMzv(x z^wCMA2@@?$uWlKa$&ce?+AzZjIhDwyWJ9&)jmY{))MIkGni?{N3$m`pL9|Y+K$6zG zdfNtH1qu4#B{^lNgU40g{+18oX+3uO{KOQdb>?npiuL;Zb+wRofuD#QE zyK#EtK}G)X%fSQ%QbuwdY{yXXm>y+t1SIR^y(L^j z7Gc5mvca;0gL;UJ`3@v-WdOp=m*g z;yReKVZ+Hr(GC9x6uxf5eFVh+B_%oA40Pgda?U+G#dGmEaJ5)=ux#mIC(93% zSRDowrwvWI@MuO)!Woj6&DNcHxlMXS9Zu>7)^sUh4OBEeE4|cn`czMw)TgFLGGh|V zr(;S(vb*gOCot9|S#x@@J64yz-6chNYDkz6pBWlfjkugjxmLucRG^X*mlNu^k<`*r zmfD8tb*zk0b#io)WLXMsAWH8jvlMD)&zdJOD?I^;Z9NC(g_af0>+4>sX_!jgN-fsJ z3N^7}&B1FYmqS%ITYr{&PyQ(M{BmV=zUII}Wy@nyIJ{7K(rT4AAMU4IVNx$$C80L?L5NE-0yH)a#+wH8rOXOf~@RoA@!zT;E@2ie<)3d<^&R z3|e%gQ-fy9r0_X*6N6^oW~o6#zR{qYL6Bq6vGdXo2^GnYW*^BhAL5Jw3Q@4@Ropp2|!IxQZYH|T)ncQU{%-gc4!CcB?O6gkTDF#M83{J0w}Oy zunlV2rl(=>HDpZW=s$+U#zObJaCC*+;_G}C3!hdut|B(D?IyDnj!YfAb@08GUmTh4 znSJTEFFn})r|2J|%aQtg!^!!`sgENKD_$7+g&zf~@>RVH;_)YsEvR%-sI)$09_ab1 z_C>LyAa+owbgt{WK#dzc6+O*pE+Ue2J58H?$3pB}Yw(z#{m{=td2_`4{{M^^=Icn` zrFBr(ejo<4kqWf$#))OL&(aXRoc1@+JH_S+8=IS;OyNm900?w3Irb8x`xGzDc}1W(bG@w$b3W${81xKs{iVK11g@ykS&AZ;E0eM%$8CaK?rn}D z7xFUXihY?qAjm=Pi|3_d89gBbe#WG+M<39z0N_O80&qG0Q4QP(&d8E%d8Zvu`yd@6 z2>_s^rW0D4B6gjTNI)uUB#4krM$YbZ@$QUH!f1k5O-jqs1)@Nv3A7?Ox72w?6=^7w zPJlm>(~6d@EBAAb1nSy+Pb0d*ig>UD;xT!1OcpZvls2Ja3*5Zx;fQ)VhI<_{IYYf{ zSU@My3IV!}^hT&=cR!8vO#`bK4AuV%iH-BtdExL1SLKT>iIqP;{qE^Sac@D~J1_40 z)bWAQLQVAE3&on&YbPJuUhvJ2LK5|YZS$4wOO-X05je^Sb@g{DZdXi)Z;R7!&Q8uu z7U~Wx*0vUETZ^?vZgNZE`sqj^y!&4D1Emmcdzko3!Rs!|aFc z!QLSID9A&(FDj6W0AW~fV2K{{ZYF&`;T$8H#m^G2i*}z<+fy6Is#Ml3X zn?k-aZ@F2x=^~mj-1t5R9}t{R0*BB~xl+)1jT?fy=~Y2toqq8DaH|CW&y2bp1?$^S z&gC!$U9aXq8~FGDf6i>+LuPb~GrE*JTAc-EXo1Lm!o#3*z#$-|-U>Q_FL-+dcrmolq zL#!rSTZ)6}#TQHD%G)M^QF=)!mAqiGW6B|u)5am_<&wa9W<_Qk?&qrM8&NMS$ziy< zQkI~+66H-Fy>iowxIkpY$$UOBl1X2rY=PT|UJhj(wJewH6(-5|NauA(K 0: - print("OK: Registros carregados") - else: - print("FALHA: Nenhum registro carregado") - except Exception as e: - print(f"FALHA: Erro ao carregar registros -> {e}") - - def test_invalid_records_ignored(self): - print("\n[TESTE 2] Validação de registros inválidos") - - try: - records = self.service.get_all_records() - - for r in records: - if r.id <= 0 or not r.name or not r.address: - print("FALHA: Registro inválido não foi filtrado") - return - - print("OK: Registros inválidos ignorados corretamente") - - except Exception as e: - print(f"FALHA: Erro durante validação -> {e}") - - def test_search_multiple_terms(self): - print("\n[TESTE 3] Busca com múltiplos termos") - - try: - self.service.get_all_records() - - results = self.service.search("joao rua a") - - if len(results) == 0: - print("FALHA: Nenhum resultado encontrado") - return - - for r in results: - text = (r.name + " " + r.address).lower() - if "joao" not in text or "rua" not in text or "a" not in text: - print("FALHA: Resultado incorreto na busca") - return - - print("OK: Busca múltiplos termos funcionando") - - except Exception as e: - print(f"FALHA: Erro na busca -> {e}") - -def calculate_file_hash(file_path): - try: - hash_md5 = hashlib.md5() - - with open(file_path, "rb") as f: - for chunk in iter(lambda: f.read(4096), b""): - hash_md5.update(chunk) - - return hash_md5.hexdigest() - - except Exception as e: - print(f"Erro ao calcular hash: {e}") - return None - -if __name__ == "__main__": - TestRunner().run() \ No newline at end of file From f48a3041a5d7374a6ad052985a59e56c23648f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Davi=20Witalo=20F=C3=A9lix=20da=20Silva?= Date: Fri, 22 May 2026 23:21:04 -0300 Subject: [PATCH 03/12] Delete Guia2 directory --- Guia2/README.md | 155 ------------------ Guia2/pytest.ini | 3 - Guia2/requirements.txt | 0 Guia2/run_tests.bat | 2 - Guia2/src/__init__.py | 1 - .../src/__pycache__/__init__.cpython-312.pyc | Bin 274 -> 0 bytes Guia2/src/folha_pagamento/__init__.py | 4 - .../__pycache__/__init__.cpython-312.pyc | Bin 358 -> 0 bytes .../__pycache__/desenvolvedor.cpython-312.pyc | Bin 419 -> 0 bytes .../__pycache__/estagiario.cpython-312.pyc | Bin 413 -> 0 bytes .../__pycache__/funcionario.cpython-312.pyc | Bin 3389 -> 0 bytes .../__pycache__/gerente.cpython-312.pyc | Bin 407 -> 0 bytes Guia2/src/folha_pagamento/desenvolvedor.py | 6 - Guia2/src/folha_pagamento/estagiario.py | 6 - Guia2/src/folha_pagamento/funcionario.py | 77 --------- Guia2/src/folha_pagamento/gerente.py | 6 - Guia2/tests/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 156 -> 0 bytes ...desenvolvedor.cpython-312-pytest-8.3.5.pyc | Bin 5824 -> 0 bytes ...st_estagiario.cpython-312-pytest-8.3.5.pyc | Bin 5706 -> 0 bytes .../test_gerente.cpython-312-pytest-8.3.5.pyc | Bin 5809 -> 0 bytes Guia2/tests/integrity.py | 32 ---- Guia2/tests/test_desenvolvedor.py | 44 ----- Guia2/tests/test_estagiario.py | 38 ----- Guia2/tests/test_gerente.py | 47 ------ 25 files changed, 421 deletions(-) delete mode 100644 Guia2/README.md delete mode 100644 Guia2/pytest.ini delete mode 100644 Guia2/requirements.txt delete mode 100644 Guia2/run_tests.bat delete mode 100644 Guia2/src/__init__.py delete mode 100644 Guia2/src/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia2/src/folha_pagamento/__init__.py delete mode 100644 Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc delete mode 100644 Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc delete mode 100644 Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc delete mode 100644 Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc delete mode 100644 Guia2/src/folha_pagamento/desenvolvedor.py delete mode 100644 Guia2/src/folha_pagamento/estagiario.py delete mode 100644 Guia2/src/folha_pagamento/funcionario.py delete mode 100644 Guia2/src/folha_pagamento/gerente.py delete mode 100644 Guia2/tests/__init__.py delete mode 100644 Guia2/tests/__pycache__/__init__.cpython-312.pyc delete mode 100644 Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc delete mode 100644 Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc delete mode 100644 Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc delete mode 100644 Guia2/tests/integrity.py delete mode 100644 Guia2/tests/test_desenvolvedor.py delete mode 100644 Guia2/tests/test_estagiario.py delete mode 100644 Guia2/tests/test_gerente.py diff --git a/Guia2/README.md b/Guia2/README.md deleted file mode 100644 index 56985d6..0000000 --- a/Guia2/README.md +++ /dev/null @@ -1,155 +0,0 @@ -# Guia 2 — Sistema de Folha de Pagamento (RH) - -## Contexto - -Você faz parte da equipe responsável por manter um módulo de **Folha de Pagamento** dentro de um sistema de **Recursos Humanos (RH)**. - -Esse módulo calcula informações básicas de funcionários de diferentes cargos, como: - -- nome -- matricula -- salario_base - -Atualmente o sistema possui uma hierarquia de classes para representar funcionários, mas carece implementar as subclasses de acordo com o diagrama UML abaixo: - - -------------------------------- - | Funcionario | - -------------------------------- - | - nome | - | - matricula | - | - salario_base | - -------------------------------- - | + dados_basicos() | - | + gerar_contracheque() | - | + calcular_salario_liquido() | - | # calcular_bonus() | - | # calcular_descontos() | - | # calcular_adicionais() | - -------------------------------- - ▲ - ----------------------------------------- - | | | - | | | - ----------------- ----------------- ----------------- - | Desenvolvedor | | Gerente | | Estagiari o | - ----------------- ----------------- ----------------- - | linguagem | | setor | | curso | - | senioridade | | qtd_equipe | | carga_horaria | - ----------------- ----------------- ----------------- - -Seu papel é implementar as subclasses passando nos testes propostos. - ---- - -## 1. Desenvolvedor - -### Atributos adicionais - -- `linguagem` -- `senioridade` - -### Regras - -#### `calcular_bonus()` - -O bônus depende da senioridade: - -| Senioridade | Bônus | -|-------------|----------------------| -| junior | 5% do salário base | -| pleno | 10% do salário base | -| senior | 15% do salário base | - ---- - -#### `calcular_descontos()` - -Desconto fixo de **8% do salário base**. - ---- - -#### `calcular_adicionais()` - -Adicional definido pela linguagem principal: - -| Linguagem | Adicional | -|----------------|-----------| -| Python | +500 | -| Java | +400 | -| JavaScript | +350 | -| Qualquer outra | +200 | - ---- - -## 2. Gerente - -### Atributos adicionais - -- `setor` -- `qtd_equipe` - -### Regras - -#### `calcular_bonus()` - -O bônus depende da quantidade de pessoas na equipe: - -| Tamanho da equipe | Bônus | -|-------------------|---------------------| -| até 5 | 10% do salário base | -| de 6 até 10 | 15% do salário base | -| acima de 10 | 20% do salário base | - ---- - -#### `calcular_descontos()` - -Desconto fixo de **12% do salário base**. - ---- - -#### `calcular_adicionais()` - -Adicional por responsabilidade: - -| Quantidade da equipe | Adicional | -|----------------------|-----------| -| equipe > 10 | +2000 | -| equipe > 5 | +1000 | -| caso contrário | +500 | - ---- - -## 3. Estagiario - -### Atributos adicionais - -- `curso` -- `carga_horaria` - -### Regras - -#### `calcular_bonus()` - -Bônus fixo de **3% do salário base**. - ---- - -#### `calcular_descontos()` - -Desconto fixo de **2% do salário base**. - ---- - -#### `calcular_adicionais()` - -Auxílio baseado na carga horária: - -| Carga horária | Adicional | -|---------------|-----------| -| até 20h | +150 | -| até 30h | +250 | -| acima de 30h | +350 | - ---- -995b5983a8b684cba7bbc7f802c760906f0d690c1e90bf440631cfe486082eb3 \ No newline at end of file diff --git a/Guia2/pytest.ini b/Guia2/pytest.ini deleted file mode 100644 index 97a0030..0000000 --- a/Guia2/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -pythonpath = src -testpaths = tests \ No newline at end of file diff --git a/Guia2/requirements.txt b/Guia2/requirements.txt deleted file mode 100644 index e69de29..0000000 diff --git a/Guia2/run_tests.bat b/Guia2/run_tests.bat deleted file mode 100644 index a2937ce..0000000 --- a/Guia2/run_tests.bat +++ /dev/null @@ -1,2 +0,0 @@ -pytest -v -pause \ No newline at end of file diff --git a/Guia2/src/__init__.py b/Guia2/src/__init__.py deleted file mode 100644 index 5d96e84..0000000 --- a/Guia2/src/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from folha_pagamento import Estagiario, Gerente, Desenvolvedor, Funcionario diff --git a/Guia2/src/__pycache__/__init__.cpython-312.pyc b/Guia2/src/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 73e61bee553995b8bd027336b80c464892268f93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274 zcmXwxJx&8L6ol>dhMz>MT!0H~LqP{ZH2kE9AT%^9OO};=BnJPiZ0|}r2@MzEEVNW^ zD5&U=(xu{Af|2HX^Q6(dSJjxHUf0v7TfATS`B(85wnrFVNK0C(iJ=WOMN=5oFjF=q zC7YsV-?>_sX?z``Tq)_5OZzkMU?ZgJ3If={=>b~j)8wYNOXX}X-PNNseRO&)MJHF% zVBdL$TfWQ~W$Yo|$QDU%-+e!o~`3lE*+vtG#)9{iFEp{$BR h9Cw@D!MSm5ui?T^aEYQr4nK@i`bp*=WbO~~{{@WEN-zKb diff --git a/Guia2/src/folha_pagamento/__init__.py b/Guia2/src/folha_pagamento/__init__.py deleted file mode 100644 index 63a2be0..0000000 --- a/Guia2/src/folha_pagamento/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .funcionario import Funcionario -from .estagiario import Estagiario -from .desenvolvedor import Desenvolvedor -from .gerente import Gerente diff --git a/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index c9423a903a7dca7b90ee06f3f9aa6224229a09cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 358 zcmYjMyH3L}6t(lLQUYRULJVYKKuid+@TgcQ3rl3lvKluH*l}bhk-G2^Ed2()g+GWC z7A7{NZk@O;<#DBZea^AYx%O)uM+oX^w)5}|=es38XlRLxg|GpVvh@N>Nl$@Z6K W7sjWHG49bpkM?_X_=fiM7N}opPh`0O diff --git a/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc deleted file mode 100644 index 4184750c23ee8739353eb22bf091220842d63946..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 419 zcmZ8dJx{|h5WP!MDgB6$SXo)Jbbt*Z77*Q97M948WyNj@Byn&)q^_v{p}zs~Q}_cY z5@KLtLu5eegq^ekagv|kv+tgL_w0EC(DAm|yM566yAiu^wxl`KWDOiR#*kou2o_9$ zTPxu9lhtJf*3$8NA4d3C4=>9!jAY7GB*QMDL)?mHq{$it1js?xqHopSg~&x($+!|+ zs;O_+E~P0;1f}(W(nRtyHhe_seaYhP<`EiWxtX4ykn3EioK!3>1kql1h0Ms+Y-Sc! zB9mlNM(l{>DkO6m-!Pi7g|<%%N%-HV$JtW#v}p^5|Lhn8`c&MHQTtST`OnG)6z^N-`DVIBjPI@f4hkNFVN7|`~bVbXleie diff --git a/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc deleted file mode 100644 index 065df0dbcb89a046b855bcc4ae46a3e63fcf4c99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 413 zcmZ8dJx{|h5WP!MDNP$8v9hvc=>Qu-EPQl8qAVmI$Vy;D`PSz&(e~U6RvJcQIN~Y#4IX# zA;`E&*d9?bB2$rGGg`2jE}xfz@ZWbw#a#Au#TE=v1{Uz*xY7)&JvX1*`B!5!{cBj- nn@rg^tThfaTe*i_A4k&H(#%3_YxuAc@fG&JT*Uq-XlOk@grQ}} diff --git a/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc deleted file mode 100644 index a87ac567fc05396055a7991980519217e7f7a3ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3389 zcmbsrO>Yxd@a>o5&vkHc8=E9{5}+}KfKs?rh|&T@&^A;JJQaZH#6^J zKHq*Hi-ifm!H?tDJ`WP|J5IVFbcpsLAXbS&6hC z<>vzmzrxQ7YCsWGZk|;FEBw>Wve`bD+vnj1Z7vVGK@T?s>%+hc!EOs*(jX zBWvrAz{YHO{cAnDs4HsLP-(WTF34u_raqbDt?);(R#DGUs#8mlY$t`KZ7;9GL_H}AOpRZ1$g%UnK$#7;RqvtQ`Ss1e^xcFoBCq@!%LU&lc>6==g(J) z@>JfSh5Wp(U6rLpc|k6zWmC`3ZwG90amflwQn6e#C8@gC6Uxah7f&@V0=i9piVysp z7}^+~tS63cM34R&AGD{(>xmN^(G#1ISJy^=i0rd@Z`Bj0H=?IElc~G>r{QLL9ENyv zICq!-F_><{Zo~>u)vVBR!3_{Fk+zc}4Fn_wxdx*jX2=s}I>*o`2%az$qh{d3EbRwu zd#&2LBoygu3?+7A~pjsXHE?Hydb@Zdr-HT>1c7bDG~Y-8w1ZRkid znOeQ_;7TKTxRyM;6%zWxEh2=%y>3Jo+HSlJ#0%VrIzH&W09D|F^SUpUN6V*yZNmqy z2E2eX#K~UX?kbj8kTq;=RGQPv6~h{E=dx0?8+*~P5-w9wje-tc#OQJBpsUkOG_81} z0!_5K-|OM$X&r_u8|MIlv!nfu=x{AM+!PZHakM6m*2VEHj*0ExM8?6Ic(5)`Yzb^E z*9wsMKtnuG6A#qI*S7k&*hGulH3C=J0R^1`3VI3!TdNa#!HIa-6X=i|Un}klV=m;`WFKxa)ZK|@ zkjf$&MKp%U*A}hBf=VIFFniz^>8g68qE<(|nb9jh4*M9N0O~0~Z{2yTv5}mpB`501 zL(TL^BRy41Pu0`Mp=ukcW3|+=dTOef8E<4x)-osSnNwSPLRhe&-3k^Cb<%|gVikT6 z?4o(nW0q}tHSM*-&2ZbjXJCCBixzAMMteI0NOn1h;(w^$g|>5d`piAcjoW!#_&TDV z#|@Y-eN+~7tC?NR+D@1EKxzA|>0H822`el~C0(g#(0r|^B;BaUn$wCc4t|dlZc zE2PCng+psIEds-1XZTiVJO<-t^kicF%H1<%y*P_*80m+g?9PI?wR>BQ$0Jpp?7?_^-Lwm61iej($3^A{N=c7OaI If}_3rzZ)*OL;wH) diff --git a/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc deleted file mode 100644 index 444c7e28d7fdbdb5546407bbd4222630c1e9431c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 407 zcmZ8dJx{|h5WP!MHT{T?SXo)Jbbt*Z77$^gEG&^F%ZlALki@}BDs}IF=x;#$6#f8; z#Kgpg$bi%dJ86Z)Nq&CMzI*oFtLF_tM}Kkfu+;m95&Ljas#><@mi%BYdn!*Hsq9GGi*1QJ2sm?nE=zWCH?1)W+U zX~t4PX+5MgmApy}A5;2Nv820shQ^p}Z!XWseIZmqmMkd+xe~==DRXi+otj0J$R!D? zn4OS9MPw$E1*18eYx}H}WZpeG$ychU?OHITFtCO<$5m!T?Ya5c(LaO9?5|a2?=#iF ku(oid+15Spnz&G&mSzgYp@uIT5#QnT$3+}`gNC-|7wB_hPXGV_ diff --git a/Guia2/src/folha_pagamento/desenvolvedor.py b/Guia2/src/folha_pagamento/desenvolvedor.py deleted file mode 100644 index 5c5d3c9..0000000 --- a/Guia2/src/folha_pagamento/desenvolvedor.py +++ /dev/null @@ -1,6 +0,0 @@ -from folha_pagamento.funcionario import Funcionario - -# Desenvolva a classe Desenvolvedor aqui. - -class Desenvolvedor: - pass \ No newline at end of file diff --git a/Guia2/src/folha_pagamento/estagiario.py b/Guia2/src/folha_pagamento/estagiario.py deleted file mode 100644 index d50a433..0000000 --- a/Guia2/src/folha_pagamento/estagiario.py +++ /dev/null @@ -1,6 +0,0 @@ -from folha_pagamento.funcionario import Funcionario - -# Desenvolva a classe Estagiario aqui. - -class Estagiario: - pass \ No newline at end of file diff --git a/Guia2/src/folha_pagamento/funcionario.py b/Guia2/src/folha_pagamento/funcionario.py deleted file mode 100644 index 0f8dccc..0000000 --- a/Guia2/src/folha_pagamento/funcionario.py +++ /dev/null @@ -1,77 +0,0 @@ -from abc import ABC, abstractmethod - -class Funcionario(ABC): - def __init__(self, nome: str, matricula: str, salario_base: float): - if not nome: - raise ValueError("Nome inválido.") - - if not matricula: - raise ValueError("Matrícula inválida.") - - if salario_base < 0: - raise ValueError("Salário não pode ser negativo.") - - self._nome = nome - self._matricula = matricula - self._salario_base = salario_base - - # --------------------------- - # Propriedades comuns - # --------------------------- - @property - def nome(self) -> str: - return self._nome - - @property - def matricula(self) -> str: - return self._matricula - - @property - def salario_base(self) -> float: - return self._salario_base - - # --------------------------- - # Métodos concretos - # --------------------------- - def dados_basicos(self) -> dict: - return { - "nome": self.nome, - "matricula": self.matricula, - "salario_base": self.salario_base, - "cargo": self.__class__.__name__ - } - - def calcular_salario_liquido(self) -> float: - return ( - self.salario_base - + self.calcular_bonus() - + self.calcular_adicionais() - - self.calcular_descontos() - ) - - def gerar_contracheque(self) -> dict: - return { - "nome": self.nome, - "matricula": self.matricula, - "cargo": self.__class__.__name__, - "salario_base": self.salario_base, - "bonus": self.calcular_bonus(), - "adicionais": self.calcular_adicionais(), - "descontos": self.calcular_descontos(), - "salario_liquido": self.calcular_salario_liquido() - } - - # --------------------------- - # Contrato abstrato - # --------------------------- - @abstractmethod - def calcular_bonus(self) -> float: - pass - - @abstractmethod - def calcular_descontos(self) -> float: - pass - - @abstractmethod - def calcular_adicionais(self) -> float: - pass \ No newline at end of file diff --git a/Guia2/src/folha_pagamento/gerente.py b/Guia2/src/folha_pagamento/gerente.py deleted file mode 100644 index 31819a1..0000000 --- a/Guia2/src/folha_pagamento/gerente.py +++ /dev/null @@ -1,6 +0,0 @@ -from folha_pagamento.funcionario import Funcionario - -# Desenvolva a classe Gerente aqui. - -class Gerente: - pass \ No newline at end of file diff --git a/Guia2/tests/__init__.py b/Guia2/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia2/tests/__pycache__/__init__.cpython-312.pyc b/Guia2/tests/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 65afc7ba052841abcb210e076b4cc2512b3b915a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmX@j%ge<81i23USs?l`h(HIQS%4zb87dhx8U0o=6fpsLpFwJVSvy7&-6@X`dxTLuH@qeV)apbnHw2>;9lJyg#itJiOilTA?8ASs@D6!(Ml$9wi zJG)dRg#_f*KyxXOo719)pePC(LJOnqAwBm}AcvBcY#9p_b0r~dL%$qkeyPR*|<0oxxSpwygg^tB3jgWt0MU+&i>^=qM4zY+O70HamuJV#n zkR`ID&ZH#Xqs?g0BNx+4nVF14Y;EzFa1>uHCRf%d>C4^%j2f)GoWTZ&n<0 zaMrgy-(xawC6_x;UJcszw9qzijf?VL0Qw&^(%Gt3e}-+ z?G)_Waj9dOmfc^rX~8b}6|-n4h8$>%73^F1#m}+an=oYB0%OAZpP(LSeE7l;D}SCS z;NC=uZryj`soo(~sY>#qk5uIKvi|G2mZiM^ZTT0Ik{aoqfz>DfX1-g$%U_=Ex-C+9oN zB`ZV8$}q2R-=oRO>mEX)TNH|?DtMV~mfiDw*`@i!oud6pcy+iz+|&(F>bi0ForXTVt>Wil*uZO%Y^cNU zkMr7QtZt!k4{v_J21Wz80`Bj=6Acq;(&&*o%s5(zUJI}X+&_C|{F-x*EJDNnQj>sX zlHf~Cwj@TqCPb{MRi&yjE~bE*DM7psB=3|j-r-~sPTc+iv_s}8I4Z$B)yEaGvdE$X zQR7#!CdRzje-k>!Bm+Xkmj98CNQeV$C2{T#u#*pI7tsl3{{P;2M0;SU)|8<~#j{G> znY0q5;I#f7^4i0o`eNaj3X&VGYH#J`Z8*2c{O)ots?>B+z`+h zn}>{Sa4ceOv?h86-JC`7DvE9t=TLkF#aB^$4aIp7f|5Ph08z#sGL9r+_&Nu6$jlry z(3mlt^D#HLr*^R!A&)Uaik0T)ofVgkf*;(t_g4_>L0r602@T>xh^K*u}hhab%6Ce&9PLvfLAO zYAov1!l*OtAC{PD@ir0HFzQTFQowQgIpHXN<4%H(=qidlj|q$T6i^J2Ddx5h?AUaF@D4zSEGXlsye}|?>no|T*$1ev6o}~~VJRv;C__1%! zJo|qv52-QyTSl+K7$lPSTM+Byad!{T3eSF>q2x)&`7kBSHS}CvodCJ14}ntGhwiU5 z^oea1KM%tOUW;Tyoj{tP#b&H-p>d8kKVSo+0bBw1_gA;G?D>9k#It5NLczpm?-ERk#sB8bU+ALTz^219i!y zHv=91HGuyCeCn*(ET3kfBf~JejTF;7wkme_pJl$e}RqpeM{O^hI_q7zr$oId?-Es3 wKFcc7$gU3B4r)(ZW$A|Wg#n{aiFOGFXfU8%maa*=9iZ-THJg$yOKiFS1}LSA7ytkO diff --git a/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc b/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc deleted file mode 100644 index bdcfb1cf5898e0a23351b53293c72bba75a5ca35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5706 zcmeHL(Qn(v8NVY>lq}hC;xw6)bg9~=h3U4c?Zio&+Nqtkt2cOQ*I^i77$X>ww&}>C zcBHe|l>lc=u|4)-XkLn;7`DQOfx?gZANDXQa^r%)unxl>i~@yQ@5xX5zB`hpQlmD4 z0O>;s@#FX1{l1UKlkUgg>F*sKSpvuEbmwe7MaX|Jhz^LwvAqVD+r%OkEs+T-uF9NR zR4AEa6DcZtv?M z;UW%;T8gDw%u20>bMQ-|YgYp8HItWIFHp}7o}U)T%Iy&-U!JzhGf>{#JPoZJYp#%O z1ngXX?c(IGJezxy*Uge|Prhz@*L=4!`Sx3H;c0NY;!eIf@0bIVzU}#*um*VHfD4s{ zAiEp#4k(Ia@_qzniTqC^?Z-cu`8f6Q_2ufFcbd78Ive3R=qtug13?>{;z|Dsb9S3l z$t*P7f7GZ#sxsIPNHk9s#e(|jH8ySD%I4r9`LlP_5t;d`_Zq4%xcLT z>03%wo1&JASyRd?3tO3wBNWH1_&r9EyhdZXPP}7@`t7YKjH+Zcd~TjZ9{Mh1nOZDS zbuTQ9s_uhR4v14D9NhW){p2hjY3d_w5x&t{+S06aHSJIlW&9)2+$QE`kCk7|M3tiJ z?}15f&>DqPfm4H1g_G4%3q;RcnZ9%S{V#uU=g+UM&>dxXSf`7%XL>3N=X5XoZs_EP z^XLskP2hx0eY#gDnx*1=$>hdWw>)e!$9#=!N+&LB3}~ zvf~<8P0!BObg}eSv_P#a^r0C*a}Lb~G%p3Lve4hR(`kCJ+p4sRnL zpg$R$O$O(a!OL=JVNOfZpzM-&>mO)|&UyH=&qoKxr5tpM2@v0wG3DHF`3umBT;}}) z%o6z`cWfhfrja{SXJcTSxo5#y#%S&2M*mo&e@w>U_M%${KrbN2HW+^HMJ+OnZG(;d z@uG~HyY4!o&&cMxA~W`v!{)ex9D%qARDi(<7c2CK_l}`)ksnAJzSAE_8YY3v?)A!v zUt|Y(Jv~B_e)q9Y-~9LDpI+si@F2j^Hy@CrE!!))W#4^BJk9Z~#Jka)z=36hu9$w~ zTk%ua|2P_ynOumsC(z5Ic@oW2Xr4xM2FzZp)g@RfDk_Pq53q+3pCGQDMy{vM#=$mo zz2GccVAdu!2FDwN<1z-ffNmWC1wf8(F#Oz$T4Wg81{+7>LP&GhT}O0}Y`!ZpV}IF_ zZfxZUq6#n=;bMis@ZK?0I#5s$*J8eC@@dnUaXISV=S|Bg!g~Z>Kekt~xoNq&rYoC| z!5nOU2nKxof$#z8<9D*TBYci80zN3)aiTYW0}2lCpeYHz0H%n_H9BI=UXV(bR*4by zp|0Iat*W4F)ks5vc4bvXDArUp<$aY#( zrOxY~6i{6eVs{~|FphGVA4P);0@dRAokIzo2x^lbhaRA*j+S*59F18kD(rX%Wh^}- z#>6k-jW42k2F{$3I8erZ;kWosEKR=AHwm4)#R|M>iOLK8spp7~2LLMT$d6bJtx*v@V

6G=KL4lB@x;D`T@x%+8>sj-_ARhySssHVVq3#!sV~P zy5qxWB$tSVA9TkIa$mgz(@0v<$m>|Sl|lFjwvB@EaN&fEAvbf~f-vs8r*XD#hW`Yh zPhrmAz$}r^pLkNx#21}UFO3PVC^T|~IvWDp%=Lj&&-JarHg0Hx;pelkK}NA{upwj$ zL^OBZbp#h=^Iee`CrAg%ufZNIOpDwk=pGvqJfR;6GSLoPNX6iUA@}SBN#&q_3f%r3 zcYN4?$4x;xY!mYxXfh>GJznGtCLl<|R@a~Bwwz_$@^X}q0h=@VwIB!Ef7sCb+*z~* z#fs_U_$Qedm6+_E%+Q=`&6n&;{B7vKf51Hae{xHul>Up5Tjaftf0C118c{NTIDPZ< z*NQ?%>9$Ig!&}1rCach&QnWv(TUkV%x_N4Yb~k8u{lqKZkn|;Go1_)>>%$7YOt+7K NyCvN$qr+k#{|B!WW?TRO diff --git a/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc b/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc deleted file mode 100644 index 42c8ece72bf1eed6daec55129e5b0f65754100e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5809 zcmd6rO>7)V6@aUMre{3uzc`R}5|Xud*Rgw@_%Dus7Hnt5;sAmyECD2AX=qQkz2nTd zXRF(bZDu3~g4pBUvLFr-0+h&?h|_X`11H3Rnb@(TmJlm(01F9u<2~iXdsSWCZD+!m zDAH1ze*LQIy;oK3uCHJD&rMBf0_FSPYgyb*5b}4dhyrz1_8-CR7O{vW<;jf1?s7rN z$`UE4GYN_JXfqo0$oXU;HItHvtu3|%{;`{-+$0-8eI^YyCt{s}x_I)*HcMR~R^pe^ zhRpjcEf%NAO5P+h&HqER6hv!?MN7w`wOBetYh9I$#$6oj>RriCUa_gYAl0CSDn87oFKF%Q$Kd^6q=gzfzgPZ!Lih7Ca(6@H_9nZ?x?=0tv z_W7bsv#{c2GoP7rmX=*ZGvr;I;6Hx;Gc3QGGGy8Sb=m>~`ZVmj$jTp~Zx>%HdW`pB z^uX^=*!LOiLy^UZqJ+=$Yw$?*V(Qq`Ck0a6DEPQ$maGmQ>Q_;qQn(^YTUz-BLVU3oDC_LW}NVtapj~ z*;xGM$UF~yM(Z_)aSM$MZ~PTqRKeQ~<)o!q$x<>Wv0BPIE}lVbE%?$LDy5VdSKNODh+2`#DqM-Own~f??BU1q#DpQO zeZ8xvxH@dO=^qA4$3zEeL!t?kplQHx`?6*}yPP*E-vsG$kC85SOmLSG!)2SxPuVVP z7t?a?s=iWO9Y8UJVi?89<7U%^o$Rr3#tau5#|+(1N88PBbWIo~=Vazg*Y=wa4(q2c z7guqYXH4oJ%Rpxy_dm@#g`!DqzY)4KbIZBBms@guE$@JZ>$hjzx1Hs@#Y{5`d1nsx z@{(Dw{f3Nd&I2im)Ng*BO)cjveThcCvU#b976}LK=|7$p_@?SM%!vXLvA+wX22To z5wP#cuQ>n6A~YN>WeJ!j3C@&dOJek^LB_ILQc5c0V*==z5afGba!+`{cZrZifsDoS!79rsPVg)6JuW#zXl~Eq5&x)%l}GABt;!tN$meRcJdMJLQ28N z|KBSQsShmGYO)kR#H_@gO^x*IsVtR%r7~O^Tnb!jIl;KP@Zs5?{Og+^{(g#Lb^(07 z@r-=6Y&YvHd5#+~wg*Fv0*+s0>jv9=r%t#^#Gg+HVWt8_tQogkfGm(S_n1if$B;O%Q6Jcoju22!YEB z*w6y5G1GV8=kZfa+6f@1t=T;m#0dbJZ?q5KxlaG*p zT~)oSqE3U{)Vo2sGYsNh_s-CCb!eK`LG4Ag0tUTcIlZIeZ(FqRYACDfG{O;0HY0Tl zt-E;hedZbJcZRtdN{cMVg8URyTKYPO+WBc8=kvk*v}Sf%R)E%u zAR`c2Ey;|-kc&bF8nLeyg(aXbW}x5`qpAA|WpYD|6mXV|on$S!4E0)P*|H3@kV9H1kiSWc7Ql_Vw18X> zXn{GO6r)ArQ>I0t4h6z}SjR4;ilsfb6@~d?U0Q^eKnpmd2Itj;m9iR2iGUW`k!hg` zN{D+v3(T*SvI==s`syxjo?JVm9D*C)eMWAG>?oguf9zOJlwQT*!47dxp+$R0i$kG~ zjEp2l2BsuWrv>hrfEMxN-=Q&s!(V2MeiiI7-Ew~oVx2rZd5RtWK5FR>PJF#py|+s(JIPZHjw`Q~BGRq7pB9=Wqil;a>EB3@6r@l~dtmV8tNv}Z% zCQ$BsAodhVlKw`>P4eTWzmgaBG$N;ddiKWIk7ZdJ*;k0%x`*0c8rx6bIK3maSEcsK y$&p7SIWF&$q^x}0sz?L-$3WXd?NOsFU6Gz}7z2mT3kO-63LH>NtI}(1rvCvcfpkFt diff --git a/Guia2/tests/integrity.py b/Guia2/tests/integrity.py deleted file mode 100644 index 6d3ebd9..0000000 --- a/Guia2/tests/integrity.py +++ /dev/null @@ -1,32 +0,0 @@ -from pathlib import Path -import hashlib - - -def gerar_hash_pasta(pasta=".", extensao=".py"): - arquivos = sorted( - [ - arquivo - for arquivo in Path(pasta).rglob(f"*{extensao}") - if arquivo.name != "integrity.py" - ] - ) - - print(arquivos) - - hash_global = hashlib.sha256() - - for arquivo in arquivos: - # inclui nome/caminho do arquivo no hash - hash_global.update(str(arquivo.relative_to(pasta)).encode()) - - # inclui conteúdo - with open(arquivo, "rb") as f: - while bloco := f.read(4096): - hash_global.update(bloco) - - return hash_global.hexdigest() - - -if __name__ == "__main__": - resultado = gerar_hash_pasta() - print(resultado) \ No newline at end of file diff --git a/Guia2/tests/test_desenvolvedor.py b/Guia2/tests/test_desenvolvedor.py deleted file mode 100644 index 0ee0137..0000000 --- a/Guia2/tests/test_desenvolvedor.py +++ /dev/null @@ -1,44 +0,0 @@ -import pytest -from src import Desenvolvedor - - -@pytest.fixture -def desenvolvedor(): - # Instância base com salário 5000, linguagem Python, senioridade pleno - return Desenvolvedor("Ana", "123", 5000.0, "Python", "pleno") - -# ---- Testes para calcular_bonus() ---- -@pytest.mark.parametrize("senioridade,percentual", [ - ("junior", 0.05), - ("pleno", 0.10), - ("senior", 0.15), -]) -def test_bonus_por_senioridade(desenvolvedor, senioridade, percentual): - desenvolvedor.senioridade = senioridade - esperado = percentual * desenvolvedor.salario_base - assert desenvolvedor.calcular_bonus() == esperado - -# ---- Teste para calcular_descontos() ---- -def test_desconto_fixo(desenvolvedor): - # 8% do salário base - assert desenvolvedor.calcular_descontos() == 0.08 * desenvolvedor.salario_base - -# ---- Testes para calcular_adicionais() ---- -@pytest.mark.parametrize("linguagem,adicional_esperado", [ - ("Python", 500), - ("Java", 400), - ("JavaScript", 350), - ("C++", 200), - ("Ruby", 200), -]) -def test_adicional_por_linguagem(desenvolvedor, linguagem, adicional_esperado): - desenvolvedor.linguagem = linguagem - assert desenvolvedor.calcular_adicionais() == adicional_esperado - -# ---- Teste integrado de salário líquido ---- -def test_salario_liquido_pleno_python(desenvolvedor): - desenvolvedor.senioridade = "pleno" - desenvolvedor.linguagem = "Python" - # salario_base (5000) + bonus(10%) + adicional(500) - desconto(8%) - esperado = 5000 + 500 + 500 - 400 # 5600 - assert desenvolvedor.calcular_salario_liquido() == esperado \ No newline at end of file diff --git a/Guia2/tests/test_estagiario.py b/Guia2/tests/test_estagiario.py deleted file mode 100644 index e1007fe..0000000 --- a/Guia2/tests/test_estagiario.py +++ /dev/null @@ -1,38 +0,0 @@ -import pytest -from src import Estagiario - - -@pytest.fixture -def estagiario(): - # Salário base 1500, carga horária 30h - return Estagiario("Carlos", "456", 1500.0, "Engenharia", 30) - -# ---- Teste do bônus fixo ---- -def test_bonus_fixo(estagiario): - # 3% do salário base - assert estagiario.calcular_bonus() == 0.03 * estagiario.salario_base - -# ---- Teste do desconto fixo ---- -def test_desconto_fixo(estagiario): - # 2% do salário base - assert estagiario.calcular_descontos() == 0.02 * estagiario.salario_base - -# ---- Testes de adicionais por carga horária ---- -@pytest.mark.parametrize("carga_horaria,adicional_esperado", [ - (20, 150), - (15, 150), # até 20h inclusive - (25, 250), - (30, 250), # até 30h inclusive - (35, 350), - (40, 350), -]) -def test_adicional_por_carga_horaria(estagiario, carga_horaria, adicional_esperado): - estagiario.carga_horaria = carga_horaria - assert estagiario.calcular_adicionais() == adicional_esperado - -# ---- Teste de salário líquido para carga de 30h ---- -def test_salario_liquido_30h(estagiario): - estagiario.carga_horaria = 30 - # 1500 + 45 (bônus) + 250 (adicional) - 30 (desconto) = 1765 - esperado = 1500 + 45 + 250 - 30 - assert estagiario.calcular_salario_liquido() == esperado \ No newline at end of file diff --git a/Guia2/tests/test_gerente.py b/Guia2/tests/test_gerente.py deleted file mode 100644 index da59182..0000000 --- a/Guia2/tests/test_gerente.py +++ /dev/null @@ -1,47 +0,0 @@ -import pytest -from src import Gerente - - -@pytest.fixture -def gerente(): - # Salário base 8000, equipe = 5 (para teste básico) - return Gerente("Roberta", "789", 8000.0, "TI", 5) - -# ---- Testes de bônus por tamanho da equipe ---- -@pytest.mark.parametrize("qtd_equipe,percentual_bonus", [ - (3, 0.10), - (5, 0.10), - (6, 0.15), - (10, 0.15), - (11, 0.20), - (20, 0.20), -]) -def test_bonus_por_tamanho_equipe(gerente, qtd_equipe, percentual_bonus): - gerente.qtd_equipe = qtd_equipe - esperado = percentual_bonus * gerente.salario_base - assert gerente.calcular_bonus() == esperado - -# ---- Teste de desconto fixo ---- -def test_desconto_fixo(gerente): - # 12% do salário base - assert gerente.calcular_descontos() == 0.12 * gerente.salario_base - -# ---- Testes de adicional por tamanho da equipe ---- -@pytest.mark.parametrize("qtd_equipe,adicional_esperado", [ - (1, 500), - (5, 500), - (6, 1000), - (10, 1000), - (11, 2000), - (15, 2000), -]) -def test_adicional_por_tamanho_equipe(gerente, qtd_equipe, adicional_esperado): - gerente.qtd_equipe = qtd_equipe - assert gerente.calcular_adicionais() == adicional_esperado - -# ---- Teste integrado para equipe de 8 pessoas ---- -def test_salario_liquido_equipe_8(gerente): - gerente.qtd_equipe = 8 - # bonus 15% = 1200, adicional = 1000, desconto 12% = 960 - esperado = 8000 + 1200 + 1000 - 960 # 9240 - assert gerente.calcular_salario_liquido() == esperado \ No newline at end of file From 2a9fd083d1b84af0b9ac4bbc88343799473e3500 Mon Sep 17 00:00:00 2001 From: serelepe Date: Sat, 30 May 2026 13:53:26 -0300 Subject: [PATCH 04/12] Reorganiza estrutura: remove subpasta POO redundante --- {POO/Guia1 => Guia1}/README.md | 402 +++++++++--------- {POO/Guia1 => Guia1}/data/records.csv | 10 +- {POO/Guia1 => Guia1}/data/records_teste.csv | 14 +- {POO/Guia1 => Guia1}/src/__init__.py | 0 .../src/__pycache__/__init__.cpython-312.pyc | Bin .../src/__pycache__/__init__.cpython-314.pyc | Bin .../src/__pycache__/main.cpython-312.pyc | Bin {POO/Guia1 => Guia1}/src/config/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../__pycache__/settings.cpython-312.pyc | Bin .../__pycache__/settings.cpython-314.pyc | Bin {POO/Guia1 => Guia1}/src/config/settings.py | 8 +- {POO/Guia1 => Guia1}/src/main.py | 60 +-- {POO/Guia1 => Guia1}/src/models/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../models/__pycache__/record.cpython-312.pyc | Bin .../models/__pycache__/record.cpython-314.pyc | Bin {POO/Guia1 => Guia1}/src/models/record.py | 68 +-- .../src/repositories/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../abstract_repository.cpython-312.pyc | Bin .../abstract_repository.cpython-314.pyc | Bin .../record_repository.cpython-312.pyc | Bin .../record_repository.cpython-314.pyc | Bin .../src/repositories/abstract_repository.py | 20 +- .../src/repositories/record_repository.py | 102 ++--- {POO/Guia1 => Guia1}/src/services/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../record_service.cpython-312.pyc | Bin .../record_service.cpython-314.pyc | Bin .../src/services/record_service.py | 26 +- {POO/Guia1 => Guia1}/src/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../__pycache__/file_loader.cpython-312.pyc | Bin .../__pycache__/file_loader.cpython-314.pyc | Bin {POO/Guia1 => Guia1}/src/utils/file_loader.py | 26 +- {POO/Guia1 => Guia1}/tests/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../__pycache__/test_runner.cpython-312.pyc | Bin .../__pycache__/test_runner.cpython-314.pyc | Bin {POO/Guia1 => Guia1}/tests/test_runner.py | 184 ++++---- {POO/Guia2 => Guia2}/README.md | 308 +++++++------- {POO/Guia2 => Guia2}/pytest.ini | 4 +- {POO/Guia2 => Guia2}/requirements.txt | 0 {POO/Guia2 => Guia2}/run_tests.bat | 2 +- {POO/Guia2 => Guia2}/src/__init__.py | 2 +- .../src/__pycache__/__init__.cpython-312.pyc | Bin .../src/__pycache__/__init__.cpython-314.pyc | Bin .../src/folha_pagamento/__init__.py | 8 +- .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin .../__pycache__/desenvolvedor.cpython-312.pyc | Bin .../__pycache__/desenvolvedor.cpython-314.pyc | Bin .../__pycache__/estagiario.cpython-312.pyc | Bin .../__pycache__/estagiario.cpython-314.pyc | Bin .../__pycache__/funcionario.cpython-312.pyc | Bin .../__pycache__/funcionario.cpython-314.pyc | Bin .../__pycache__/gerente.cpython-312.pyc | Bin .../__pycache__/gerente.cpython-314.pyc | Bin .../src/folha_pagamento/desenvolvedor.py | 74 ++-- .../src/folha_pagamento/estagiario.py | 52 +-- .../src/folha_pagamento/funcionario.py | 152 +++---- .../src/folha_pagamento/gerente.py | 68 +-- {POO/Guia2 => Guia2}/tests/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin .../__pycache__/__init__.cpython-314.pyc | Bin ...desenvolvedor.cpython-312-pytest-8.3.5.pyc | Bin ...desenvolvedor.cpython-314-pytest-9.0.3.pyc | Bin ...st_estagiario.cpython-312-pytest-8.3.5.pyc | Bin ...st_estagiario.cpython-314-pytest-9.0.3.pyc | Bin .../test_gerente.cpython-312-pytest-8.3.5.pyc | Bin .../test_gerente.cpython-314-pytest-9.0.3.pyc | Bin {POO/Guia2 => Guia2}/tests/integrity.py | 62 +-- .../tests/test_desenvolvedor.py | 86 ++-- {POO/Guia2 => Guia2}/tests/test_estagiario.py | 74 ++-- {POO/Guia2 => Guia2}/tests/test_gerente.py | 92 ++-- 82 files changed, 952 insertions(+), 952 deletions(-) rename {POO/Guia1 => Guia1}/README.md (94%) rename {POO/Guia1 => Guia1}/data/records.csv (96%) rename {POO/Guia1 => Guia1}/data/records_teste.csv (95%) rename {POO/Guia1 => Guia1}/src/__init__.py (100%) rename {POO/Guia1 => Guia1}/src/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/__pycache__/main.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/config/__init__.py (100%) rename {POO/Guia1 => Guia1}/src/config/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/config/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/config/__pycache__/settings.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/config/__pycache__/settings.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/config/settings.py (97%) rename {POO/Guia1 => Guia1}/src/main.py (96%) rename {POO/Guia1 => Guia1}/src/models/__init__.py (100%) rename {POO/Guia1 => Guia1}/src/models/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/models/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/models/__pycache__/record.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/models/__pycache__/record.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/models/record.py (96%) rename {POO/Guia1 => Guia1}/src/repositories/__init__.py (100%) rename {POO/Guia1 => Guia1}/src/repositories/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/repositories/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/repositories/__pycache__/abstract_repository.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/repositories/__pycache__/abstract_repository.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/repositories/__pycache__/record_repository.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/repositories/__pycache__/record_repository.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/repositories/abstract_repository.py (95%) rename {POO/Guia1 => Guia1}/src/repositories/record_repository.py (96%) rename {POO/Guia1 => Guia1}/src/services/__init__.py (100%) rename {POO/Guia1 => Guia1}/src/services/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/services/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/services/__pycache__/record_service.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/services/__pycache__/record_service.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/services/record_service.py (97%) rename {POO/Guia1 => Guia1}/src/utils/__init__.py (100%) rename {POO/Guia1 => Guia1}/src/utils/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/utils/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/utils/__pycache__/file_loader.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/src/utils/__pycache__/file_loader.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/src/utils/file_loader.py (97%) rename {POO/Guia1 => Guia1}/tests/__init__.py (100%) rename {POO/Guia1 => Guia1}/tests/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/tests/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/tests/__pycache__/test_runner.cpython-312.pyc (100%) rename {POO/Guia1 => Guia1}/tests/__pycache__/test_runner.cpython-314.pyc (100%) rename {POO/Guia1 => Guia1}/tests/test_runner.py (96%) rename {POO/Guia2 => Guia2}/README.md (96%) rename {POO/Guia2 => Guia2}/pytest.ini (95%) rename {POO/Guia2 => Guia2}/requirements.txt (100%) rename {POO/Guia2 => Guia2}/run_tests.bat (93%) rename {POO/Guia2 => Guia2}/src/__init__.py (98%) rename {POO/Guia2 => Guia2}/src/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/src/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__init__.py (97%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/desenvolvedor.py (96%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/estagiario.py (96%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/funcionario.py (96%) rename {POO/Guia2 => Guia2}/src/folha_pagamento/gerente.py (96%) rename {POO/Guia2 => Guia2}/tests/__init__.py (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/__init__.cpython-312.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/__init__.cpython-314.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc (100%) rename {POO/Guia2 => Guia2}/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc (100%) rename {POO/Guia2 => Guia2}/tests/integrity.py (96%) rename {POO/Guia2 => Guia2}/tests/test_desenvolvedor.py (97%) rename {POO/Guia2 => Guia2}/tests/test_estagiario.py (97%) rename {POO/Guia2 => Guia2}/tests/test_gerente.py (96%) diff --git a/POO/Guia1/README.md b/Guia1/README.md similarity index 94% rename from POO/Guia1/README.md rename to Guia1/README.md index e978c4a..8bdcc3b 100644 --- a/POO/Guia1/README.md +++ b/Guia1/README.md @@ -1,202 +1,202 @@ -# Guia 1 - Carregando Dados - - -Este projeto tem como objetivo praticar conceitos de Programação Orientada a Objetos (POO) em Python, utilizando uma aplicação simples baseada em leitura de arquivos, criação de objetos e processamento em memória. - ---- - -## 🎯 Objetivo - -Você deve analisar o código existente e implementar melhorias para que o sistema: - -- Valide corretamente os dados carregados do arquivo -- Permita buscas mais avançadas -- Passe em todos os testes automatizados - ---- - -## ▶️ Como executar - -### Executar aplicação - - -python -m src.main - - -### Executar testes - - -python -m tests.test_runner - - ---- - -## ✅ Critério de sucesso - -Ao executar os testes, o resultado esperado é: - -- Todos os testes com status **OK** -- Nenhuma mensagem contendo **FALHA** - -Se houver qualquer **FALHA**, o sistema ainda está incorreto. - ---- - -## 🧩 ISSUE 1 — Validação de Dados - -### Problema - -O sistema atualmente carrega dados do arquivo sem validação. - -Isso permite registros inválidos, como: -- ID vazio ou negativo -- Nome vazio -- Endereço vazio - ---- - -### Sua tarefa - -Implementar validação para garantir que: - -- `id` seja inteiro positivo -- `name` não seja vazio -- `address` não seja vazio - ---- - -### Regras - -- Registros inválidos devem ser ignorados -- O sistema deve continuar funcionando normalmente -- Deve ser exibida mensagem indicando o erro - ---- - -### Exemplo esperado - - -Registro inválido ignorado: {'id': '', 'name': 'Sem ID', 'address': 'Rua C'} - - ---- - -### Onde implementar - -- `models/record.py` -ou -- `repositories/record_repository.py` - ---- - -## 🧩 ISSUE 2 — Busca com Múltiplos Termos - -### Problema - -A busca atual aceita apenas um termo simples. - ---- - -### Sua tarefa - -Permitir que o usuário informe múltiplos termos: - - -joao rua a - - ---- - -### Regras - -- Separar a entrada em palavras -- A busca deve ser: - - Case-insensitive - - Aplicada em `name` e `address` -- O registro só deve ser retornado se contiver **todos os termos** - ---- - -### Exemplo esperado - -Entrada: - -joao rua a - - -Saída: - -Record(id=1, name='João Silva', address='Rua A 123') - - ---- - -### Onde implementar - -- `services/record_service.py` -ou -- `repositories/record_repository.py` - ---- - -## 🧪 Sobre os testes - -O arquivo: - - -tests/test_runner.py - - -executa automaticamente: - -- Carregamento de dados -- Validação de registros inválidos -- Busca com múltiplos termos - ---- - -## ⚠️ Importante - -- Não altere os testes -- Corrija apenas o código da aplicação -- O objetivo é fazer o sistema passar nos testes corretamente - ---- - -## 💡 Dica - -Se você precisar escolher onde implementar a lógica: - -- **Validação → Model ou Repository** -- **Regra de busca → Service ou Repository** - -Essa decisão faz parte da avaliação. - ---- - -## 🚀 Resultado esperado - -Ao final, o sistema deve: - -- Carregar apenas dados válidos -- Permitir buscas avançadas -- Executar todos os testes sem falhas - - -OK: Registros carregados -OK: Registros inválidos ignorados corretamente -OK: Busca múltiplos termos funcionando - - ---- - -## 📌 Conclusão - -Se passou nos testes sem falhas: - -✔ Você implementou corretamente -✔ Você entendeu a separação de responsabilidades -✔ Você aplicou POO de forma prática - -Caso contrário: revise sua modelagem. +# Guia 1 - Carregando Dados + + +Este projeto tem como objetivo praticar conceitos de Programação Orientada a Objetos (POO) em Python, utilizando uma aplicação simples baseada em leitura de arquivos, criação de objetos e processamento em memória. + +--- + +## 🎯 Objetivo + +Você deve analisar o código existente e implementar melhorias para que o sistema: + +- Valide corretamente os dados carregados do arquivo +- Permita buscas mais avançadas +- Passe em todos os testes automatizados + +--- + +## ▶️ Como executar + +### Executar aplicação + + +python -m src.main + + +### Executar testes + + +python -m tests.test_runner + + +--- + +## ✅ Critério de sucesso + +Ao executar os testes, o resultado esperado é: + +- Todos os testes com status **OK** +- Nenhuma mensagem contendo **FALHA** + +Se houver qualquer **FALHA**, o sistema ainda está incorreto. + +--- + +## 🧩 ISSUE 1 — Validação de Dados + +### Problema + +O sistema atualmente carrega dados do arquivo sem validação. + +Isso permite registros inválidos, como: +- ID vazio ou negativo +- Nome vazio +- Endereço vazio + +--- + +### Sua tarefa + +Implementar validação para garantir que: + +- `id` seja inteiro positivo +- `name` não seja vazio +- `address` não seja vazio + +--- + +### Regras + +- Registros inválidos devem ser ignorados +- O sistema deve continuar funcionando normalmente +- Deve ser exibida mensagem indicando o erro + +--- + +### Exemplo esperado + + +Registro inválido ignorado: {'id': '', 'name': 'Sem ID', 'address': 'Rua C'} + + +--- + +### Onde implementar + +- `models/record.py` +ou +- `repositories/record_repository.py` + +--- + +## 🧩 ISSUE 2 — Busca com Múltiplos Termos + +### Problema + +A busca atual aceita apenas um termo simples. + +--- + +### Sua tarefa + +Permitir que o usuário informe múltiplos termos: + + +joao rua a + + +--- + +### Regras + +- Separar a entrada em palavras +- A busca deve ser: + - Case-insensitive + - Aplicada em `name` e `address` +- O registro só deve ser retornado se contiver **todos os termos** + +--- + +### Exemplo esperado + +Entrada: + +joao rua a + + +Saída: + +Record(id=1, name='João Silva', address='Rua A 123') + + +--- + +### Onde implementar + +- `services/record_service.py` +ou +- `repositories/record_repository.py` + +--- + +## 🧪 Sobre os testes + +O arquivo: + + +tests/test_runner.py + + +executa automaticamente: + +- Carregamento de dados +- Validação de registros inválidos +- Busca com múltiplos termos + +--- + +## ⚠️ Importante + +- Não altere os testes +- Corrija apenas o código da aplicação +- O objetivo é fazer o sistema passar nos testes corretamente + +--- + +## 💡 Dica + +Se você precisar escolher onde implementar a lógica: + +- **Validação → Model ou Repository** +- **Regra de busca → Service ou Repository** + +Essa decisão faz parte da avaliação. + +--- + +## 🚀 Resultado esperado + +Ao final, o sistema deve: + +- Carregar apenas dados válidos +- Permitir buscas avançadas +- Executar todos os testes sem falhas + + +OK: Registros carregados +OK: Registros inválidos ignorados corretamente +OK: Busca múltiplos termos funcionando + + +--- + +## 📌 Conclusão + +Se passou nos testes sem falhas: + +✔ Você implementou corretamente +✔ Você entendeu a separação de responsabilidades +✔ Você aplicou POO de forma prática + +Caso contrário: revise sua modelagem. >>77f39f6cb45e487337a25f811b074ceb<< \ No newline at end of file diff --git a/POO/Guia1/data/records.csv b/Guia1/data/records.csv similarity index 96% rename from POO/Guia1/data/records.csv rename to Guia1/data/records.csv index d93a3ca..a672050 100644 --- a/POO/Guia1/data/records.csv +++ b/Guia1/data/records.csv @@ -1,6 +1,6 @@ -id,name,address -1,João Silva,Rua A 123 -2,Maria Souza,Rua B 456 -3,Carlos Lima,Rua C 789 -4,Ana Paula,Rua A 999 +id,name,address +1,João Silva,Rua A 123 +2,Maria Souza,Rua B 456 +3,Carlos Lima,Rua C 789 +4,Ana Paula,Rua A 999 5,João Pedro,Rua D 321 \ No newline at end of file diff --git a/POO/Guia1/data/records_teste.csv b/Guia1/data/records_teste.csv similarity index 95% rename from POO/Guia1/data/records_teste.csv rename to Guia1/data/records_teste.csv index 56a36dd..5a3020e 100644 --- a/POO/Guia1/data/records_teste.csv +++ b/Guia1/data/records_teste.csv @@ -1,8 +1,8 @@ -id,name,address -1,João Silva,Rua A 123 -2,Maria Souza,Rua B 456 -,Sem ID,Rua C 000 -4,,Rua D 111 -5,Carlos Lima, --1,ID Negativo,Rua X +id,name,address +1,João Silva,Rua A 123 +2,Maria Souza,Rua B 456 +,Sem ID,Rua C 000 +4,,Rua D 111 +5,Carlos Lima, +-1,ID Negativo,Rua X 6,Ana Paula,Rua A 999s \ No newline at end of file diff --git a/POO/Guia1/src/__init__.py b/Guia1/src/__init__.py similarity index 100% rename from POO/Guia1/src/__init__.py rename to Guia1/src/__init__.py diff --git a/POO/Guia1/src/__pycache__/__init__.cpython-312.pyc b/Guia1/src/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/__pycache__/__init__.cpython-312.pyc rename to Guia1/src/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/src/__pycache__/__init__.cpython-314.pyc b/Guia1/src/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/__pycache__/__init__.cpython-314.pyc rename to Guia1/src/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/src/__pycache__/main.cpython-312.pyc b/Guia1/src/__pycache__/main.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/__pycache__/main.cpython-312.pyc rename to Guia1/src/__pycache__/main.cpython-312.pyc diff --git a/POO/Guia1/src/config/__init__.py b/Guia1/src/config/__init__.py similarity index 100% rename from POO/Guia1/src/config/__init__.py rename to Guia1/src/config/__init__.py diff --git a/POO/Guia1/src/config/__pycache__/__init__.cpython-312.pyc b/Guia1/src/config/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/config/__pycache__/__init__.cpython-312.pyc rename to Guia1/src/config/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/src/config/__pycache__/__init__.cpython-314.pyc b/Guia1/src/config/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/config/__pycache__/__init__.cpython-314.pyc rename to Guia1/src/config/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/src/config/__pycache__/settings.cpython-312.pyc b/Guia1/src/config/__pycache__/settings.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/config/__pycache__/settings.cpython-312.pyc rename to Guia1/src/config/__pycache__/settings.cpython-312.pyc diff --git a/POO/Guia1/src/config/__pycache__/settings.cpython-314.pyc b/Guia1/src/config/__pycache__/settings.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/config/__pycache__/settings.cpython-314.pyc rename to Guia1/src/config/__pycache__/settings.cpython-314.pyc diff --git a/POO/Guia1/src/config/settings.py b/Guia1/src/config/settings.py similarity index 97% rename from POO/Guia1/src/config/settings.py rename to Guia1/src/config/settings.py index bc893c6..254197a 100644 --- a/POO/Guia1/src/config/settings.py +++ b/Guia1/src/config/settings.py @@ -1,5 +1,5 @@ -import os - -class Settings: - BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) +import os + +class Settings: + BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) DATA_FILE = os.path.join(BASE_DIR, "data", "records.csv") \ No newline at end of file diff --git a/POO/Guia1/src/main.py b/Guia1/src/main.py similarity index 96% rename from POO/Guia1/src/main.py rename to Guia1/src/main.py index 0907e9f..d460e33 100644 --- a/POO/Guia1/src/main.py +++ b/Guia1/src/main.py @@ -1,31 +1,31 @@ -from src.services.record_service import RecordService -from src.config.settings import Settings - -def main(): - service = RecordService(Settings.DATA_FILE) - - print("=== CARREGANDO REGISTROS ===") - try: - records = service.get_all_records() - for r in records: - print(r) - except Exception as e: - print(f"Erro: {e}") - return - - print("\n=== BUSCA ===") - term = input("Digite nome ou endereço: ") - - try: - results = service.search(term) - if results: - for r in results: - print(r) - else: - print("Nenhum registro encontrado.") - except Exception as e: - print(f"Erro: {e}") - - -if __name__ == "__main__": +from src.services.record_service import RecordService +from src.config.settings import Settings + +def main(): + service = RecordService(Settings.DATA_FILE) + + print("=== CARREGANDO REGISTROS ===") + try: + records = service.get_all_records() + for r in records: + print(r) + except Exception as e: + print(f"Erro: {e}") + return + + print("\n=== BUSCA ===") + term = input("Digite nome ou endereço: ") + + try: + results = service.search(term) + if results: + for r in results: + print(r) + else: + print("Nenhum registro encontrado.") + except Exception as e: + print(f"Erro: {e}") + + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/POO/Guia1/src/models/__init__.py b/Guia1/src/models/__init__.py similarity index 100% rename from POO/Guia1/src/models/__init__.py rename to Guia1/src/models/__init__.py diff --git a/POO/Guia1/src/models/__pycache__/__init__.cpython-312.pyc b/Guia1/src/models/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/models/__pycache__/__init__.cpython-312.pyc rename to Guia1/src/models/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/src/models/__pycache__/__init__.cpython-314.pyc b/Guia1/src/models/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/models/__pycache__/__init__.cpython-314.pyc rename to Guia1/src/models/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/src/models/__pycache__/record.cpython-312.pyc b/Guia1/src/models/__pycache__/record.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/models/__pycache__/record.cpython-312.pyc rename to Guia1/src/models/__pycache__/record.cpython-312.pyc diff --git a/POO/Guia1/src/models/__pycache__/record.cpython-314.pyc b/Guia1/src/models/__pycache__/record.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/models/__pycache__/record.cpython-314.pyc rename to Guia1/src/models/__pycache__/record.cpython-314.pyc diff --git a/POO/Guia1/src/models/record.py b/Guia1/src/models/record.py similarity index 96% rename from POO/Guia1/src/models/record.py rename to Guia1/src/models/record.py index 248db9a..40f31d3 100644 --- a/POO/Guia1/src/models/record.py +++ b/Guia1/src/models/record.py @@ -1,34 +1,34 @@ -class Record: - def __init__(self, record_id: int, name: str, address: str): - try: - id = int(record_id) - except (ValueError, TypeError): - raise ValueError("ID deve ser um número inteiro válido.") - - if id <= 0: - raise ValueError("ID inválido.") - - if not name or name.strip() == "": - raise ValueError("Nome inválido.Dont can be void") - - if not address or address.strip() == "": - raise ValueError("Endereço invalido. Dont can be void") - - self._id = id - self._name = name.strip() - self._address = address.strip() - - @property - def id(self): - return self._id - - @property - def name(self): - return self._name - - @property - def address(self): - return self._address - - def __repr__(self): - return f"Record(id={self._id}, name='{self._name}', address='{self._address}')" +class Record: + def __init__(self, record_id: int, name: str, address: str): + try: + id = int(record_id) + except (ValueError, TypeError): + raise ValueError("ID deve ser um número inteiro válido.") + + if id <= 0: + raise ValueError("ID inválido.") + + if not name or name.strip() == "": + raise ValueError("Nome inválido.Dont can be void") + + if not address or address.strip() == "": + raise ValueError("Endereço invalido. Dont can be void") + + self._id = id + self._name = name.strip() + self._address = address.strip() + + @property + def id(self): + return self._id + + @property + def name(self): + return self._name + + @property + def address(self): + return self._address + + def __repr__(self): + return f"Record(id={self._id}, name='{self._name}', address='{self._address}')" diff --git a/POO/Guia1/src/repositories/__init__.py b/Guia1/src/repositories/__init__.py similarity index 100% rename from POO/Guia1/src/repositories/__init__.py rename to Guia1/src/repositories/__init__.py diff --git a/POO/Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc b/Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc rename to Guia1/src/repositories/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc b/Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc rename to Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc b/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc rename to Guia1/src/repositories/__pycache__/abstract_repository.cpython-312.pyc diff --git a/POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc b/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc rename to Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc diff --git a/POO/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc b/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc rename to Guia1/src/repositories/__pycache__/record_repository.cpython-312.pyc diff --git a/POO/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc b/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc rename to Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc diff --git a/POO/Guia1/src/repositories/abstract_repository.py b/Guia1/src/repositories/abstract_repository.py similarity index 95% rename from POO/Guia1/src/repositories/abstract_repository.py rename to Guia1/src/repositories/abstract_repository.py index f09f5db..681b898 100644 --- a/POO/Guia1/src/repositories/abstract_repository.py +++ b/Guia1/src/repositories/abstract_repository.py @@ -1,11 +1,11 @@ -from abc import ABC, abstractmethod - -class AbstractRepository(ABC): - - @abstractmethod - def load_all(self): - pass - - @abstractmethod - def search(self, term: str): +from abc import ABC, abstractmethod + +class AbstractRepository(ABC): + + @abstractmethod + def load_all(self): + pass + + @abstractmethod + def search(self, term: str): pass \ No newline at end of file diff --git a/POO/Guia1/src/repositories/record_repository.py b/Guia1/src/repositories/record_repository.py similarity index 96% rename from POO/Guia1/src/repositories/record_repository.py rename to Guia1/src/repositories/record_repository.py index 5947722..2c7e46d 100644 --- a/POO/Guia1/src/repositories/record_repository.py +++ b/Guia1/src/repositories/record_repository.py @@ -1,51 +1,51 @@ -import unicodedata - -from src.repositories.abstract_repository import AbstractRepository -from src.models.record import Record -from src.utils.file_loader import FileLoader - - -def _normalize_text(text: str) -> str: - normalized = unicodedata.normalize("NFKD", text) - return "".join(ch for ch in normalized if not unicodedata.combining(ch)).lower() - - -class RecordRepository(AbstractRepository): - def __init__(self, file_path: str): - self._file_path = file_path - self._records = [] - - def load_all(self): - data = FileLoader.load_csv(self._file_path) - self._records = [] - for row in data: - try: - novo_registro = Record(row["id"], row["name"], row["address"]) - self._records.append(novo_registro) - except ValueError: - print( - f"Registro inválido ignorado: {{'id': '{row['id']}', 'name': '{row['name']}', 'address': '{row['address']}'}}" - ) - continue - - return self._records - - def search(self, term: str): - term = _normalize_text(term) - - termos = term.split() - - if not termos: - return [] - - resultados = [] - - for r in self._records: - palavras_do_registro = ( - _normalize_text(r.name).split() + _normalize_text(r.address).split() - ) - - if all(palavra in palavras_do_registro for palavra in termos): - resultados.append(r) - - return resultados +import unicodedata + +from src.repositories.abstract_repository import AbstractRepository +from src.models.record import Record +from src.utils.file_loader import FileLoader + + +def _normalize_text(text: str) -> str: + normalized = unicodedata.normalize("NFKD", text) + return "".join(ch for ch in normalized if not unicodedata.combining(ch)).lower() + + +class RecordRepository(AbstractRepository): + def __init__(self, file_path: str): + self._file_path = file_path + self._records = [] + + def load_all(self): + data = FileLoader.load_csv(self._file_path) + self._records = [] + for row in data: + try: + novo_registro = Record(row["id"], row["name"], row["address"]) + self._records.append(novo_registro) + except ValueError: + print( + f"Registro inválido ignorado: {{'id': '{row['id']}', 'name': '{row['name']}', 'address': '{row['address']}'}}" + ) + continue + + return self._records + + def search(self, term: str): + term = _normalize_text(term) + + termos = term.split() + + if not termos: + return [] + + resultados = [] + + for r in self._records: + palavras_do_registro = ( + _normalize_text(r.name).split() + _normalize_text(r.address).split() + ) + + if all(palavra in palavras_do_registro for palavra in termos): + resultados.append(r) + + return resultados diff --git a/POO/Guia1/src/services/__init__.py b/Guia1/src/services/__init__.py similarity index 100% rename from POO/Guia1/src/services/__init__.py rename to Guia1/src/services/__init__.py diff --git a/POO/Guia1/src/services/__pycache__/__init__.cpython-312.pyc b/Guia1/src/services/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/services/__pycache__/__init__.cpython-312.pyc rename to Guia1/src/services/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/src/services/__pycache__/__init__.cpython-314.pyc b/Guia1/src/services/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/services/__pycache__/__init__.cpython-314.pyc rename to Guia1/src/services/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/src/services/__pycache__/record_service.cpython-312.pyc b/Guia1/src/services/__pycache__/record_service.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/services/__pycache__/record_service.cpython-312.pyc rename to Guia1/src/services/__pycache__/record_service.cpython-312.pyc diff --git a/POO/Guia1/src/services/__pycache__/record_service.cpython-314.pyc b/Guia1/src/services/__pycache__/record_service.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/services/__pycache__/record_service.cpython-314.pyc rename to Guia1/src/services/__pycache__/record_service.cpython-314.pyc diff --git a/POO/Guia1/src/services/record_service.py b/Guia1/src/services/record_service.py similarity index 97% rename from POO/Guia1/src/services/record_service.py rename to Guia1/src/services/record_service.py index d4ca5d9..0317c85 100644 --- a/POO/Guia1/src/services/record_service.py +++ b/Guia1/src/services/record_service.py @@ -1,14 +1,14 @@ -from src.repositories.record_repository import RecordRepository - -class RecordService: - - def __init__(self, file_path: str): - self._repository = RecordRepository(file_path) - - def get_all_records(self): - return self._repository.load_all() - - def search(self, term: str): - if not term or term.strip() == "": - raise ValueError("Termo de busca inválido") +from src.repositories.record_repository import RecordRepository + +class RecordService: + + def __init__(self, file_path: str): + self._repository = RecordRepository(file_path) + + def get_all_records(self): + return self._repository.load_all() + + def search(self, term: str): + if not term or term.strip() == "": + raise ValueError("Termo de busca inválido") return self._repository.search(term) \ No newline at end of file diff --git a/POO/Guia1/src/utils/__init__.py b/Guia1/src/utils/__init__.py similarity index 100% rename from POO/Guia1/src/utils/__init__.py rename to Guia1/src/utils/__init__.py diff --git a/POO/Guia1/src/utils/__pycache__/__init__.cpython-312.pyc b/Guia1/src/utils/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/utils/__pycache__/__init__.cpython-312.pyc rename to Guia1/src/utils/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/src/utils/__pycache__/__init__.cpython-314.pyc b/Guia1/src/utils/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/utils/__pycache__/__init__.cpython-314.pyc rename to Guia1/src/utils/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc b/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc similarity index 100% rename from POO/Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc rename to Guia1/src/utils/__pycache__/file_loader.cpython-312.pyc diff --git a/POO/Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc b/Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc similarity index 100% rename from POO/Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc rename to Guia1/src/utils/__pycache__/file_loader.cpython-314.pyc diff --git a/POO/Guia1/src/utils/file_loader.py b/Guia1/src/utils/file_loader.py similarity index 97% rename from POO/Guia1/src/utils/file_loader.py rename to Guia1/src/utils/file_loader.py index 3272122..c9afe65 100644 --- a/POO/Guia1/src/utils/file_loader.py +++ b/Guia1/src/utils/file_loader.py @@ -1,14 +1,14 @@ -import csv - -class FileLoader: - - @staticmethod - def load_csv(file_path: str): - try: - with open(file_path, mode='r', encoding='utf-8') as file: - reader = csv.DictReader(file) - return list(reader) - except FileNotFoundError: - raise Exception(f"Arquivo não encontrado: {file_path}") - except Exception as e: +import csv + +class FileLoader: + + @staticmethod + def load_csv(file_path: str): + try: + with open(file_path, mode='r', encoding='utf-8') as file: + reader = csv.DictReader(file) + return list(reader) + except FileNotFoundError: + raise Exception(f"Arquivo não encontrado: {file_path}") + except Exception as e: raise Exception(f"Erro ao ler arquivo: {str(e)}") \ No newline at end of file diff --git a/POO/Guia1/tests/__init__.py b/Guia1/tests/__init__.py similarity index 100% rename from POO/Guia1/tests/__init__.py rename to Guia1/tests/__init__.py diff --git a/POO/Guia1/tests/__pycache__/__init__.cpython-312.pyc b/Guia1/tests/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia1/tests/__pycache__/__init__.cpython-312.pyc rename to Guia1/tests/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia1/tests/__pycache__/__init__.cpython-314.pyc b/Guia1/tests/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia1/tests/__pycache__/__init__.cpython-314.pyc rename to Guia1/tests/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia1/tests/__pycache__/test_runner.cpython-312.pyc b/Guia1/tests/__pycache__/test_runner.cpython-312.pyc similarity index 100% rename from POO/Guia1/tests/__pycache__/test_runner.cpython-312.pyc rename to Guia1/tests/__pycache__/test_runner.cpython-312.pyc diff --git a/POO/Guia1/tests/__pycache__/test_runner.cpython-314.pyc b/Guia1/tests/__pycache__/test_runner.cpython-314.pyc similarity index 100% rename from POO/Guia1/tests/__pycache__/test_runner.cpython-314.pyc rename to Guia1/tests/__pycache__/test_runner.cpython-314.pyc diff --git a/POO/Guia1/tests/test_runner.py b/Guia1/tests/test_runner.py similarity index 96% rename from POO/Guia1/tests/test_runner.py rename to Guia1/tests/test_runner.py index 8af4329..5bfd179 100644 --- a/POO/Guia1/tests/test_runner.py +++ b/Guia1/tests/test_runner.py @@ -1,92 +1,92 @@ -from src.services.record_service import RecordService -from src.config.settings import Settings - -import os -import hashlib - - -class TestRunner: - def __init__(self): - base_dir = os.path.dirname(os.path.dirname(__file__)) - self.test_file = os.path.join(base_dir, "data", "records_teste.csv") - self.service = RecordService(self.test_file) - print( - f"\n{calculate_file_hash(os.path.join(base_dir, 'tests', 'test_runner.py'))}" - ) - - def run(self): - print("\n=== EXECUTANDO TESTES ===") - - self.test_load_valid_records() - self.test_invalid_records_ignored() - self.test_search_multiple_terms() - - def test_load_valid_records(self): - print("\n[TESTE 1] Carregamento básico") - - try: - records = self.service.get_all_records() - if len(records) > 0: - print("OK: Registros carregados") - else: - print("FALHA: Nenhum registro carregado") - except Exception as e: - print(f"FALHA: Erro ao carregar registros -> {e}") - - def test_invalid_records_ignored(self): - print("\n[TESTE 2] Validação de registros inválidos") - - try: - records = self.service.get_all_records() - - for r in records: - if r.id <= 0 or not r.name or not r.address: - print("FALHA: Registro inválido não foi filtrado") - return - - print("OK: Registros inválidos ignorados corretamente") - - except Exception as e: - print(f"FALHA: Erro durante validação -> {e}") - - def test_search_multiple_terms(self): - print("\n[TESTE 3] Busca com múltiplos termos") - - try: - self.service.get_all_records() - - results = self.service.search("joao rua a") - - if len(results) == 0: - print("FALHA: Nenhum resultado encontrado") - return - - for r in results: - text = (r.name + " " + r.address).lower() - if "joão" not in text or "rua" not in text or "a" not in text: - print("FALHA: Resultado incorreto na busca") - return - - print("OK: Busca múltiplos termos funcionando") - - except Exception as e: - print(f"FALHA: Erro na busca -> {e}") - - -def calculate_file_hash(file_path): - try: - hash_md5 = hashlib.md5() - - with open(file_path, "rb") as f: - for chunk in iter(lambda: f.read(4096), b""): - hash_md5.update(chunk) - - return hash_md5.hexdigest() - - except Exception as e: - print(f"Erro ao calcular hash: {e}") - return None - - -if __name__ == "__main__": - TestRunner().run() +from src.services.record_service import RecordService +from src.config.settings import Settings + +import os +import hashlib + + +class TestRunner: + def __init__(self): + base_dir = os.path.dirname(os.path.dirname(__file__)) + self.test_file = os.path.join(base_dir, "data", "records_teste.csv") + self.service = RecordService(self.test_file) + print( + f"\n{calculate_file_hash(os.path.join(base_dir, 'tests', 'test_runner.py'))}" + ) + + def run(self): + print("\n=== EXECUTANDO TESTES ===") + + self.test_load_valid_records() + self.test_invalid_records_ignored() + self.test_search_multiple_terms() + + def test_load_valid_records(self): + print("\n[TESTE 1] Carregamento básico") + + try: + records = self.service.get_all_records() + if len(records) > 0: + print("OK: Registros carregados") + else: + print("FALHA: Nenhum registro carregado") + except Exception as e: + print(f"FALHA: Erro ao carregar registros -> {e}") + + def test_invalid_records_ignored(self): + print("\n[TESTE 2] Validação de registros inválidos") + + try: + records = self.service.get_all_records() + + for r in records: + if r.id <= 0 or not r.name or not r.address: + print("FALHA: Registro inválido não foi filtrado") + return + + print("OK: Registros inválidos ignorados corretamente") + + except Exception as e: + print(f"FALHA: Erro durante validação -> {e}") + + def test_search_multiple_terms(self): + print("\n[TESTE 3] Busca com múltiplos termos") + + try: + self.service.get_all_records() + + results = self.service.search("joao rua a") + + if len(results) == 0: + print("FALHA: Nenhum resultado encontrado") + return + + for r in results: + text = (r.name + " " + r.address).lower() + if "joão" not in text or "rua" not in text or "a" not in text: + print("FALHA: Resultado incorreto na busca") + return + + print("OK: Busca múltiplos termos funcionando") + + except Exception as e: + print(f"FALHA: Erro na busca -> {e}") + + +def calculate_file_hash(file_path): + try: + hash_md5 = hashlib.md5() + + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + + return hash_md5.hexdigest() + + except Exception as e: + print(f"Erro ao calcular hash: {e}") + return None + + +if __name__ == "__main__": + TestRunner().run() diff --git a/POO/Guia2/README.md b/Guia2/README.md similarity index 96% rename from POO/Guia2/README.md rename to Guia2/README.md index 64f7194..56985d6 100644 --- a/POO/Guia2/README.md +++ b/Guia2/README.md @@ -1,155 +1,155 @@ -# Guia 2 — Sistema de Folha de Pagamento (RH) - -## Contexto - -Você faz parte da equipe responsável por manter um módulo de **Folha de Pagamento** dentro de um sistema de **Recursos Humanos (RH)**. - -Esse módulo calcula informações básicas de funcionários de diferentes cargos, como: - -- nome -- matricula -- salario_base - -Atualmente o sistema possui uma hierarquia de classes para representar funcionários, mas carece implementar as subclasses de acordo com o diagrama UML abaixo: - - -------------------------------- - | Funcionario | - -------------------------------- - | - nome | - | - matricula | - | - salario_base | - -------------------------------- - | + dados_basicos() | - | + gerar_contracheque() | - | + calcular_salario_liquido() | - | # calcular_bonus() | - | # calcular_descontos() | - | # calcular_adicionais() | - -------------------------------- - ▲ - ----------------------------------------- - | | | - | | | - ----------------- ----------------- ----------------- - | Desenvolvedor | | Gerente | | Estagiari o | - ----------------- ----------------- ----------------- - | linguagem | | setor | | curso | - | senioridade | | qtd_equipe | | carga_horaria | - ----------------- ----------------- ----------------- - -Seu papel é implementar as subclasses passando nos testes propostos. - ---- - -## 1. Desenvolvedor - -### Atributos adicionais - -- `linguagem` -- `senioridade` - -### Regras - -#### `calcular_bonus()` - -O bônus depende da senioridade: - -| Senioridade | Bônus | -|-------------|----------------------| -| junior | 5% do salário base | -| pleno | 10% do salário base | -| senior | 15% do salário base | - ---- - -#### `calcular_descontos()` - -Desconto fixo de **8% do salário base**. - ---- - -#### `calcular_adicionais()` - -Adicional definido pela linguagem principal: - -| Linguagem | Adicional | -|----------------|-----------| -| Python | +500 | -| Java | +400 | -| JavaScript | +350 | -| Qualquer outra | +200 | - ---- - -## 2. Gerente - -### Atributos adicionais - -- `setor` -- `qtd_equipe` - -### Regras - -#### `calcular_bonus()` - -O bônus depende da quantidade de pessoas na equipe: - -| Tamanho da equipe | Bônus | -|-------------------|---------------------| -| até 5 | 10% do salário base | -| de 6 até 10 | 15% do salário base | -| acima de 10 | 20% do salário base | - ---- - -#### `calcular_descontos()` - -Desconto fixo de **12% do salário base**. - ---- - -#### `calcular_adicionais()` - -Adicional por responsabilidade: - -| Quantidade da equipe | Adicional | -|----------------------|-----------| -| equipe > 10 | +2000 | -| equipe > 5 | +1000 | -| caso contrário | +500 | - ---- - -## 3. Estagiario - -### Atributos adicionais - -- `curso` -- `carga_horaria` - -### Regras - -#### `calcular_bonus()` - -Bônus fixo de **3% do salário base**. - ---- - -#### `calcular_descontos()` - -Desconto fixo de **2% do salário base**. - ---- - -#### `calcular_adicionais()` - -Auxílio baseado na carga horária: - -| Carga horária | Adicional | -|---------------|-----------| -| até 20h | +150 | -| até 30h | +250 | -| acima de 30h | +350 | - ---- +# Guia 2 — Sistema de Folha de Pagamento (RH) + +## Contexto + +Você faz parte da equipe responsável por manter um módulo de **Folha de Pagamento** dentro de um sistema de **Recursos Humanos (RH)**. + +Esse módulo calcula informações básicas de funcionários de diferentes cargos, como: + +- nome +- matricula +- salario_base + +Atualmente o sistema possui uma hierarquia de classes para representar funcionários, mas carece implementar as subclasses de acordo com o diagrama UML abaixo: + + -------------------------------- + | Funcionario | + -------------------------------- + | - nome | + | - matricula | + | - salario_base | + -------------------------------- + | + dados_basicos() | + | + gerar_contracheque() | + | + calcular_salario_liquido() | + | # calcular_bonus() | + | # calcular_descontos() | + | # calcular_adicionais() | + -------------------------------- + ▲ + ----------------------------------------- + | | | + | | | + ----------------- ----------------- ----------------- + | Desenvolvedor | | Gerente | | Estagiari o | + ----------------- ----------------- ----------------- + | linguagem | | setor | | curso | + | senioridade | | qtd_equipe | | carga_horaria | + ----------------- ----------------- ----------------- + +Seu papel é implementar as subclasses passando nos testes propostos. + +--- + +## 1. Desenvolvedor + +### Atributos adicionais + +- `linguagem` +- `senioridade` + +### Regras + +#### `calcular_bonus()` + +O bônus depende da senioridade: + +| Senioridade | Bônus | +|-------------|----------------------| +| junior | 5% do salário base | +| pleno | 10% do salário base | +| senior | 15% do salário base | + +--- + +#### `calcular_descontos()` + +Desconto fixo de **8% do salário base**. + +--- + +#### `calcular_adicionais()` + +Adicional definido pela linguagem principal: + +| Linguagem | Adicional | +|----------------|-----------| +| Python | +500 | +| Java | +400 | +| JavaScript | +350 | +| Qualquer outra | +200 | + +--- + +## 2. Gerente + +### Atributos adicionais + +- `setor` +- `qtd_equipe` + +### Regras + +#### `calcular_bonus()` + +O bônus depende da quantidade de pessoas na equipe: + +| Tamanho da equipe | Bônus | +|-------------------|---------------------| +| até 5 | 10% do salário base | +| de 6 até 10 | 15% do salário base | +| acima de 10 | 20% do salário base | + +--- + +#### `calcular_descontos()` + +Desconto fixo de **12% do salário base**. + +--- + +#### `calcular_adicionais()` + +Adicional por responsabilidade: + +| Quantidade da equipe | Adicional | +|----------------------|-----------| +| equipe > 10 | +2000 | +| equipe > 5 | +1000 | +| caso contrário | +500 | + +--- + +## 3. Estagiario + +### Atributos adicionais + +- `curso` +- `carga_horaria` + +### Regras + +#### `calcular_bonus()` + +Bônus fixo de **3% do salário base**. + +--- + +#### `calcular_descontos()` + +Desconto fixo de **2% do salário base**. + +--- + +#### `calcular_adicionais()` + +Auxílio baseado na carga horária: + +| Carga horária | Adicional | +|---------------|-----------| +| até 20h | +150 | +| até 30h | +250 | +| acima de 30h | +350 | + +--- 995b5983a8b684cba7bbc7f802c760906f0d690c1e90bf440631cfe486082eb3 \ No newline at end of file diff --git a/POO/Guia2/pytest.ini b/Guia2/pytest.ini similarity index 95% rename from POO/Guia2/pytest.ini rename to Guia2/pytest.ini index 87b077a..97a0030 100644 --- a/POO/Guia2/pytest.ini +++ b/Guia2/pytest.ini @@ -1,3 +1,3 @@ -[pytest] -pythonpath = src +[pytest] +pythonpath = src testpaths = tests \ No newline at end of file diff --git a/POO/Guia2/requirements.txt b/Guia2/requirements.txt similarity index 100% rename from POO/Guia2/requirements.txt rename to Guia2/requirements.txt diff --git a/POO/Guia2/run_tests.bat b/Guia2/run_tests.bat similarity index 93% rename from POO/Guia2/run_tests.bat rename to Guia2/run_tests.bat index a171223..a2937ce 100644 --- a/POO/Guia2/run_tests.bat +++ b/Guia2/run_tests.bat @@ -1,2 +1,2 @@ -pytest -v +pytest -v pause \ No newline at end of file diff --git a/POO/Guia2/src/__init__.py b/Guia2/src/__init__.py similarity index 98% rename from POO/Guia2/src/__init__.py rename to Guia2/src/__init__.py index e436592..5d96e84 100644 --- a/POO/Guia2/src/__init__.py +++ b/Guia2/src/__init__.py @@ -1 +1 @@ -from folha_pagamento import Estagiario, Gerente, Desenvolvedor, Funcionario +from folha_pagamento import Estagiario, Gerente, Desenvolvedor, Funcionario diff --git a/POO/Guia2/src/__pycache__/__init__.cpython-312.pyc b/Guia2/src/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia2/src/__pycache__/__init__.cpython-312.pyc rename to Guia2/src/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia2/src/__pycache__/__init__.cpython-314.pyc b/Guia2/src/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia2/src/__pycache__/__init__.cpython-314.pyc rename to Guia2/src/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia2/src/folha_pagamento/__init__.py b/Guia2/src/folha_pagamento/__init__.py similarity index 97% rename from POO/Guia2/src/folha_pagamento/__init__.py rename to Guia2/src/folha_pagamento/__init__.py index 968df16..63a2be0 100644 --- a/POO/Guia2/src/folha_pagamento/__init__.py +++ b/Guia2/src/folha_pagamento/__init__.py @@ -1,4 +1,4 @@ -from .funcionario import Funcionario -from .estagiario import Estagiario -from .desenvolvedor import Desenvolvedor -from .gerente import Gerente +from .funcionario import Funcionario +from .estagiario import Estagiario +from .desenvolvedor import Desenvolvedor +from .gerente import Gerente diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc rename to Guia2/src/folha_pagamento/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc b/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc rename to Guia2/src/folha_pagamento/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc rename to Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-312.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc b/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc rename to Guia2/src/folha_pagamento/__pycache__/desenvolvedor.cpython-314.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc rename to Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-312.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc b/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc rename to Guia2/src/folha_pagamento/__pycache__/estagiario.cpython-314.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc rename to Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-312.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc b/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc rename to Guia2/src/folha_pagamento/__pycache__/funcionario.cpython-314.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc b/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc rename to Guia2/src/folha_pagamento/__pycache__/gerente.cpython-312.pyc diff --git a/POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc b/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc similarity index 100% rename from POO/Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc rename to Guia2/src/folha_pagamento/__pycache__/gerente.cpython-314.pyc diff --git a/POO/Guia2/src/folha_pagamento/desenvolvedor.py b/Guia2/src/folha_pagamento/desenvolvedor.py similarity index 96% rename from POO/Guia2/src/folha_pagamento/desenvolvedor.py rename to Guia2/src/folha_pagamento/desenvolvedor.py index c58d949..7adcf02 100644 --- a/POO/Guia2/src/folha_pagamento/desenvolvedor.py +++ b/Guia2/src/folha_pagamento/desenvolvedor.py @@ -1,37 +1,37 @@ -from folha_pagamento.funcionario import Funcionario - -# Desenvolva a classe Desenvolvedor aqui. - - -class Desenvolvedor(Funcionario): - def __init__(self, nome, matricula, salario_base, linguagem, senioridade): - super().__init__(nome, matricula, salario_base) - self.linguagem = linguagem - self.senioridade = senioridade - - def calcular_bonus(self): - if self.senioridade == "junior": - bonus = 5 / 100 - return self._salario_base * bonus - - if self.senioridade == "pleno": - bonus = 10 / 100 - return self._salario_base * bonus - - if self.senioridade == "senior": - bonus = 15 / 100 - return self._salario_base * bonus - - def calcular_descontos(self): - return self._salario_base * (8 / 100) - - def calcular_adicionais(self): - - if self.linguagem == "Python": - return 500 - if self.linguagem == "Java": - return 400 - if self.linguagem == "JavaScript": - return 350 - else: - return 200 +from folha_pagamento.funcionario import Funcionario + +# Desenvolva a classe Desenvolvedor aqui. + + +class Desenvolvedor(Funcionario): + def __init__(self, nome, matricula, salario_base, linguagem, senioridade): + super().__init__(nome, matricula, salario_base) + self.linguagem = linguagem + self.senioridade = senioridade + + def calcular_bonus(self): + if self.senioridade == "junior": + bonus = 5 / 100 + return self._salario_base * bonus + + if self.senioridade == "pleno": + bonus = 10 / 100 + return self._salario_base * bonus + + if self.senioridade == "senior": + bonus = 15 / 100 + return self._salario_base * bonus + + def calcular_descontos(self): + return self._salario_base * (8 / 100) + + def calcular_adicionais(self): + + if self.linguagem == "Python": + return 500 + if self.linguagem == "Java": + return 400 + if self.linguagem == "JavaScript": + return 350 + else: + return 200 diff --git a/POO/Guia2/src/folha_pagamento/estagiario.py b/Guia2/src/folha_pagamento/estagiario.py similarity index 96% rename from POO/Guia2/src/folha_pagamento/estagiario.py rename to Guia2/src/folha_pagamento/estagiario.py index d504cf0..fff23a6 100644 --- a/POO/Guia2/src/folha_pagamento/estagiario.py +++ b/Guia2/src/folha_pagamento/estagiario.py @@ -1,26 +1,26 @@ -from folha_pagamento.funcionario import Funcionario - -# Desenvolva a classe Estagiario aqui. - - -class Estagiario(Funcionario): - def __init__(self, nome, matricula, salario_base, curso, carga_horaria): - super().__init__(nome, matricula, salario_base) - self.curso = curso - self.carga_horaria = carga_horaria - - def calcular_bonus(self): - return self._salario_base * (3 / 100) - - def calcular_descontos(self): - return self._salario_base * 0.02 - - def calcular_adicionais(self): - if self.carga_horaria <= 20: - return 150 - - elif self.carga_horaria <= 30: - return 250 - - else: - return 350 +from folha_pagamento.funcionario import Funcionario + +# Desenvolva a classe Estagiario aqui. + + +class Estagiario(Funcionario): + def __init__(self, nome, matricula, salario_base, curso, carga_horaria): + super().__init__(nome, matricula, salario_base) + self.curso = curso + self.carga_horaria = carga_horaria + + def calcular_bonus(self): + return self._salario_base * (3 / 100) + + def calcular_descontos(self): + return self._salario_base * 0.02 + + def calcular_adicionais(self): + if self.carga_horaria <= 20: + return 150 + + elif self.carga_horaria <= 30: + return 250 + + else: + return 350 diff --git a/POO/Guia2/src/folha_pagamento/funcionario.py b/Guia2/src/folha_pagamento/funcionario.py similarity index 96% rename from POO/Guia2/src/folha_pagamento/funcionario.py rename to Guia2/src/folha_pagamento/funcionario.py index add2716..0f8dccc 100644 --- a/POO/Guia2/src/folha_pagamento/funcionario.py +++ b/Guia2/src/folha_pagamento/funcionario.py @@ -1,77 +1,77 @@ -from abc import ABC, abstractmethod - -class Funcionario(ABC): - def __init__(self, nome: str, matricula: str, salario_base: float): - if not nome: - raise ValueError("Nome inválido.") - - if not matricula: - raise ValueError("Matrícula inválida.") - - if salario_base < 0: - raise ValueError("Salário não pode ser negativo.") - - self._nome = nome - self._matricula = matricula - self._salario_base = salario_base - - # --------------------------- - # Propriedades comuns - # --------------------------- - @property - def nome(self) -> str: - return self._nome - - @property - def matricula(self) -> str: - return self._matricula - - @property - def salario_base(self) -> float: - return self._salario_base - - # --------------------------- - # Métodos concretos - # --------------------------- - def dados_basicos(self) -> dict: - return { - "nome": self.nome, - "matricula": self.matricula, - "salario_base": self.salario_base, - "cargo": self.__class__.__name__ - } - - def calcular_salario_liquido(self) -> float: - return ( - self.salario_base - + self.calcular_bonus() - + self.calcular_adicionais() - - self.calcular_descontos() - ) - - def gerar_contracheque(self) -> dict: - return { - "nome": self.nome, - "matricula": self.matricula, - "cargo": self.__class__.__name__, - "salario_base": self.salario_base, - "bonus": self.calcular_bonus(), - "adicionais": self.calcular_adicionais(), - "descontos": self.calcular_descontos(), - "salario_liquido": self.calcular_salario_liquido() - } - - # --------------------------- - # Contrato abstrato - # --------------------------- - @abstractmethod - def calcular_bonus(self) -> float: - pass - - @abstractmethod - def calcular_descontos(self) -> float: - pass - - @abstractmethod - def calcular_adicionais(self) -> float: +from abc import ABC, abstractmethod + +class Funcionario(ABC): + def __init__(self, nome: str, matricula: str, salario_base: float): + if not nome: + raise ValueError("Nome inválido.") + + if not matricula: + raise ValueError("Matrícula inválida.") + + if salario_base < 0: + raise ValueError("Salário não pode ser negativo.") + + self._nome = nome + self._matricula = matricula + self._salario_base = salario_base + + # --------------------------- + # Propriedades comuns + # --------------------------- + @property + def nome(self) -> str: + return self._nome + + @property + def matricula(self) -> str: + return self._matricula + + @property + def salario_base(self) -> float: + return self._salario_base + + # --------------------------- + # Métodos concretos + # --------------------------- + def dados_basicos(self) -> dict: + return { + "nome": self.nome, + "matricula": self.matricula, + "salario_base": self.salario_base, + "cargo": self.__class__.__name__ + } + + def calcular_salario_liquido(self) -> float: + return ( + self.salario_base + + self.calcular_bonus() + + self.calcular_adicionais() + - self.calcular_descontos() + ) + + def gerar_contracheque(self) -> dict: + return { + "nome": self.nome, + "matricula": self.matricula, + "cargo": self.__class__.__name__, + "salario_base": self.salario_base, + "bonus": self.calcular_bonus(), + "adicionais": self.calcular_adicionais(), + "descontos": self.calcular_descontos(), + "salario_liquido": self.calcular_salario_liquido() + } + + # --------------------------- + # Contrato abstrato + # --------------------------- + @abstractmethod + def calcular_bonus(self) -> float: + pass + + @abstractmethod + def calcular_descontos(self) -> float: + pass + + @abstractmethod + def calcular_adicionais(self) -> float: pass \ No newline at end of file diff --git a/POO/Guia2/src/folha_pagamento/gerente.py b/Guia2/src/folha_pagamento/gerente.py similarity index 96% rename from POO/Guia2/src/folha_pagamento/gerente.py rename to Guia2/src/folha_pagamento/gerente.py index 171e1d9..ddb97ad 100644 --- a/POO/Guia2/src/folha_pagamento/gerente.py +++ b/Guia2/src/folha_pagamento/gerente.py @@ -1,34 +1,34 @@ -from folha_pagamento.funcionario import Funcionario - -# Desenvolva a classe Gerente aqui. - - -class Gerente(Funcionario): - def __init__(self, nome, matricula, salario_base, setor, qtd_equipe): - super().__init__(nome, matricula, salario_base) - self.setor = setor - self.qtd_equipe = qtd_equipe - - def calcular_bonus(self): - - if self.qtd_equipe <= 5: - return self._salario_base * 0.10 - - elif self.qtd_equipe <= 10: - return self._salario_base * 0.15 - - if self.qtd_equipe > 10: - return self._salario_base * 0.20 - - def calcular_descontos(self): - return self._salario_base * 0.12 - - def calcular_adicionais(self): - if self.qtd_equipe > 10: - return 2000 - - elif self.qtd_equipe > 5: - return 1000 - - else: - return 500 +from folha_pagamento.funcionario import Funcionario + +# Desenvolva a classe Gerente aqui. + + +class Gerente(Funcionario): + def __init__(self, nome, matricula, salario_base, setor, qtd_equipe): + super().__init__(nome, matricula, salario_base) + self.setor = setor + self.qtd_equipe = qtd_equipe + + def calcular_bonus(self): + + if self.qtd_equipe <= 5: + return self._salario_base * 0.10 + + elif self.qtd_equipe <= 10: + return self._salario_base * 0.15 + + if self.qtd_equipe > 10: + return self._salario_base * 0.20 + + def calcular_descontos(self): + return self._salario_base * 0.12 + + def calcular_adicionais(self): + if self.qtd_equipe > 10: + return 2000 + + elif self.qtd_equipe > 5: + return 1000 + + else: + return 500 diff --git a/POO/Guia2/tests/__init__.py b/Guia2/tests/__init__.py similarity index 100% rename from POO/Guia2/tests/__init__.py rename to Guia2/tests/__init__.py diff --git a/POO/Guia2/tests/__pycache__/__init__.cpython-312.pyc b/Guia2/tests/__pycache__/__init__.cpython-312.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/__init__.cpython-312.pyc rename to Guia2/tests/__pycache__/__init__.cpython-312.pyc diff --git a/POO/Guia2/tests/__pycache__/__init__.cpython-314.pyc b/Guia2/tests/__pycache__/__init__.cpython-314.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/__init__.cpython-314.pyc rename to Guia2/tests/__pycache__/__init__.cpython-314.pyc diff --git a/POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc b/Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc rename to Guia2/tests/__pycache__/test_desenvolvedor.cpython-312-pytest-8.3.5.pyc diff --git a/POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc b/Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc rename to Guia2/tests/__pycache__/test_desenvolvedor.cpython-314-pytest-9.0.3.pyc diff --git a/POO/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc b/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc rename to Guia2/tests/__pycache__/test_estagiario.cpython-312-pytest-8.3.5.pyc diff --git a/POO/Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc b/Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc rename to Guia2/tests/__pycache__/test_estagiario.cpython-314-pytest-9.0.3.pyc diff --git a/POO/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc b/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc rename to Guia2/tests/__pycache__/test_gerente.cpython-312-pytest-8.3.5.pyc diff --git a/POO/Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc b/Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc similarity index 100% rename from POO/Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc rename to Guia2/tests/__pycache__/test_gerente.cpython-314-pytest-9.0.3.pyc diff --git a/POO/Guia2/tests/integrity.py b/Guia2/tests/integrity.py similarity index 96% rename from POO/Guia2/tests/integrity.py rename to Guia2/tests/integrity.py index faee152..6d3ebd9 100644 --- a/POO/Guia2/tests/integrity.py +++ b/Guia2/tests/integrity.py @@ -1,32 +1,32 @@ -from pathlib import Path -import hashlib - - -def gerar_hash_pasta(pasta=".", extensao=".py"): - arquivos = sorted( - [ - arquivo - for arquivo in Path(pasta).rglob(f"*{extensao}") - if arquivo.name != "integrity.py" - ] - ) - - print(arquivos) - - hash_global = hashlib.sha256() - - for arquivo in arquivos: - # inclui nome/caminho do arquivo no hash - hash_global.update(str(arquivo.relative_to(pasta)).encode()) - - # inclui conteúdo - with open(arquivo, "rb") as f: - while bloco := f.read(4096): - hash_global.update(bloco) - - return hash_global.hexdigest() - - -if __name__ == "__main__": - resultado = gerar_hash_pasta() +from pathlib import Path +import hashlib + + +def gerar_hash_pasta(pasta=".", extensao=".py"): + arquivos = sorted( + [ + arquivo + for arquivo in Path(pasta).rglob(f"*{extensao}") + if arquivo.name != "integrity.py" + ] + ) + + print(arquivos) + + hash_global = hashlib.sha256() + + for arquivo in arquivos: + # inclui nome/caminho do arquivo no hash + hash_global.update(str(arquivo.relative_to(pasta)).encode()) + + # inclui conteúdo + with open(arquivo, "rb") as f: + while bloco := f.read(4096): + hash_global.update(bloco) + + return hash_global.hexdigest() + + +if __name__ == "__main__": + resultado = gerar_hash_pasta() print(resultado) \ No newline at end of file diff --git a/POO/Guia2/tests/test_desenvolvedor.py b/Guia2/tests/test_desenvolvedor.py similarity index 97% rename from POO/Guia2/tests/test_desenvolvedor.py rename to Guia2/tests/test_desenvolvedor.py index 40fa4b6..0ee0137 100644 --- a/POO/Guia2/tests/test_desenvolvedor.py +++ b/Guia2/tests/test_desenvolvedor.py @@ -1,44 +1,44 @@ -import pytest -from src import Desenvolvedor - - -@pytest.fixture -def desenvolvedor(): - # Instância base com salário 5000, linguagem Python, senioridade pleno - return Desenvolvedor("Ana", "123", 5000.0, "Python", "pleno") - -# ---- Testes para calcular_bonus() ---- -@pytest.mark.parametrize("senioridade,percentual", [ - ("junior", 0.05), - ("pleno", 0.10), - ("senior", 0.15), -]) -def test_bonus_por_senioridade(desenvolvedor, senioridade, percentual): - desenvolvedor.senioridade = senioridade - esperado = percentual * desenvolvedor.salario_base - assert desenvolvedor.calcular_bonus() == esperado - -# ---- Teste para calcular_descontos() ---- -def test_desconto_fixo(desenvolvedor): - # 8% do salário base - assert desenvolvedor.calcular_descontos() == 0.08 * desenvolvedor.salario_base - -# ---- Testes para calcular_adicionais() ---- -@pytest.mark.parametrize("linguagem,adicional_esperado", [ - ("Python", 500), - ("Java", 400), - ("JavaScript", 350), - ("C++", 200), - ("Ruby", 200), -]) -def test_adicional_por_linguagem(desenvolvedor, linguagem, adicional_esperado): - desenvolvedor.linguagem = linguagem - assert desenvolvedor.calcular_adicionais() == adicional_esperado - -# ---- Teste integrado de salário líquido ---- -def test_salario_liquido_pleno_python(desenvolvedor): - desenvolvedor.senioridade = "pleno" - desenvolvedor.linguagem = "Python" - # salario_base (5000) + bonus(10%) + adicional(500) - desconto(8%) - esperado = 5000 + 500 + 500 - 400 # 5600 +import pytest +from src import Desenvolvedor + + +@pytest.fixture +def desenvolvedor(): + # Instância base com salário 5000, linguagem Python, senioridade pleno + return Desenvolvedor("Ana", "123", 5000.0, "Python", "pleno") + +# ---- Testes para calcular_bonus() ---- +@pytest.mark.parametrize("senioridade,percentual", [ + ("junior", 0.05), + ("pleno", 0.10), + ("senior", 0.15), +]) +def test_bonus_por_senioridade(desenvolvedor, senioridade, percentual): + desenvolvedor.senioridade = senioridade + esperado = percentual * desenvolvedor.salario_base + assert desenvolvedor.calcular_bonus() == esperado + +# ---- Teste para calcular_descontos() ---- +def test_desconto_fixo(desenvolvedor): + # 8% do salário base + assert desenvolvedor.calcular_descontos() == 0.08 * desenvolvedor.salario_base + +# ---- Testes para calcular_adicionais() ---- +@pytest.mark.parametrize("linguagem,adicional_esperado", [ + ("Python", 500), + ("Java", 400), + ("JavaScript", 350), + ("C++", 200), + ("Ruby", 200), +]) +def test_adicional_por_linguagem(desenvolvedor, linguagem, adicional_esperado): + desenvolvedor.linguagem = linguagem + assert desenvolvedor.calcular_adicionais() == adicional_esperado + +# ---- Teste integrado de salário líquido ---- +def test_salario_liquido_pleno_python(desenvolvedor): + desenvolvedor.senioridade = "pleno" + desenvolvedor.linguagem = "Python" + # salario_base (5000) + bonus(10%) + adicional(500) - desconto(8%) + esperado = 5000 + 500 + 500 - 400 # 5600 assert desenvolvedor.calcular_salario_liquido() == esperado \ No newline at end of file diff --git a/POO/Guia2/tests/test_estagiario.py b/Guia2/tests/test_estagiario.py similarity index 97% rename from POO/Guia2/tests/test_estagiario.py rename to Guia2/tests/test_estagiario.py index 92591e8..e1007fe 100644 --- a/POO/Guia2/tests/test_estagiario.py +++ b/Guia2/tests/test_estagiario.py @@ -1,38 +1,38 @@ -import pytest -from src import Estagiario - - -@pytest.fixture -def estagiario(): - # Salário base 1500, carga horária 30h - return Estagiario("Carlos", "456", 1500.0, "Engenharia", 30) - -# ---- Teste do bônus fixo ---- -def test_bonus_fixo(estagiario): - # 3% do salário base - assert estagiario.calcular_bonus() == 0.03 * estagiario.salario_base - -# ---- Teste do desconto fixo ---- -def test_desconto_fixo(estagiario): - # 2% do salário base - assert estagiario.calcular_descontos() == 0.02 * estagiario.salario_base - -# ---- Testes de adicionais por carga horária ---- -@pytest.mark.parametrize("carga_horaria,adicional_esperado", [ - (20, 150), - (15, 150), # até 20h inclusive - (25, 250), - (30, 250), # até 30h inclusive - (35, 350), - (40, 350), -]) -def test_adicional_por_carga_horaria(estagiario, carga_horaria, adicional_esperado): - estagiario.carga_horaria = carga_horaria - assert estagiario.calcular_adicionais() == adicional_esperado - -# ---- Teste de salário líquido para carga de 30h ---- -def test_salario_liquido_30h(estagiario): - estagiario.carga_horaria = 30 - # 1500 + 45 (bônus) + 250 (adicional) - 30 (desconto) = 1765 - esperado = 1500 + 45 + 250 - 30 +import pytest +from src import Estagiario + + +@pytest.fixture +def estagiario(): + # Salário base 1500, carga horária 30h + return Estagiario("Carlos", "456", 1500.0, "Engenharia", 30) + +# ---- Teste do bônus fixo ---- +def test_bonus_fixo(estagiario): + # 3% do salário base + assert estagiario.calcular_bonus() == 0.03 * estagiario.salario_base + +# ---- Teste do desconto fixo ---- +def test_desconto_fixo(estagiario): + # 2% do salário base + assert estagiario.calcular_descontos() == 0.02 * estagiario.salario_base + +# ---- Testes de adicionais por carga horária ---- +@pytest.mark.parametrize("carga_horaria,adicional_esperado", [ + (20, 150), + (15, 150), # até 20h inclusive + (25, 250), + (30, 250), # até 30h inclusive + (35, 350), + (40, 350), +]) +def test_adicional_por_carga_horaria(estagiario, carga_horaria, adicional_esperado): + estagiario.carga_horaria = carga_horaria + assert estagiario.calcular_adicionais() == adicional_esperado + +# ---- Teste de salário líquido para carga de 30h ---- +def test_salario_liquido_30h(estagiario): + estagiario.carga_horaria = 30 + # 1500 + 45 (bônus) + 250 (adicional) - 30 (desconto) = 1765 + esperado = 1500 + 45 + 250 - 30 assert estagiario.calcular_salario_liquido() == esperado \ No newline at end of file diff --git a/POO/Guia2/tests/test_gerente.py b/Guia2/tests/test_gerente.py similarity index 96% rename from POO/Guia2/tests/test_gerente.py rename to Guia2/tests/test_gerente.py index ae0f7d6..da59182 100644 --- a/POO/Guia2/tests/test_gerente.py +++ b/Guia2/tests/test_gerente.py @@ -1,47 +1,47 @@ -import pytest -from src import Gerente - - -@pytest.fixture -def gerente(): - # Salário base 8000, equipe = 5 (para teste básico) - return Gerente("Roberta", "789", 8000.0, "TI", 5) - -# ---- Testes de bônus por tamanho da equipe ---- -@pytest.mark.parametrize("qtd_equipe,percentual_bonus", [ - (3, 0.10), - (5, 0.10), - (6, 0.15), - (10, 0.15), - (11, 0.20), - (20, 0.20), -]) -def test_bonus_por_tamanho_equipe(gerente, qtd_equipe, percentual_bonus): - gerente.qtd_equipe = qtd_equipe - esperado = percentual_bonus * gerente.salario_base - assert gerente.calcular_bonus() == esperado - -# ---- Teste de desconto fixo ---- -def test_desconto_fixo(gerente): - # 12% do salário base - assert gerente.calcular_descontos() == 0.12 * gerente.salario_base - -# ---- Testes de adicional por tamanho da equipe ---- -@pytest.mark.parametrize("qtd_equipe,adicional_esperado", [ - (1, 500), - (5, 500), - (6, 1000), - (10, 1000), - (11, 2000), - (15, 2000), -]) -def test_adicional_por_tamanho_equipe(gerente, qtd_equipe, adicional_esperado): - gerente.qtd_equipe = qtd_equipe - assert gerente.calcular_adicionais() == adicional_esperado - -# ---- Teste integrado para equipe de 8 pessoas ---- -def test_salario_liquido_equipe_8(gerente): - gerente.qtd_equipe = 8 - # bonus 15% = 1200, adicional = 1000, desconto 12% = 960 - esperado = 8000 + 1200 + 1000 - 960 # 9240 +import pytest +from src import Gerente + + +@pytest.fixture +def gerente(): + # Salário base 8000, equipe = 5 (para teste básico) + return Gerente("Roberta", "789", 8000.0, "TI", 5) + +# ---- Testes de bônus por tamanho da equipe ---- +@pytest.mark.parametrize("qtd_equipe,percentual_bonus", [ + (3, 0.10), + (5, 0.10), + (6, 0.15), + (10, 0.15), + (11, 0.20), + (20, 0.20), +]) +def test_bonus_por_tamanho_equipe(gerente, qtd_equipe, percentual_bonus): + gerente.qtd_equipe = qtd_equipe + esperado = percentual_bonus * gerente.salario_base + assert gerente.calcular_bonus() == esperado + +# ---- Teste de desconto fixo ---- +def test_desconto_fixo(gerente): + # 12% do salário base + assert gerente.calcular_descontos() == 0.12 * gerente.salario_base + +# ---- Testes de adicional por tamanho da equipe ---- +@pytest.mark.parametrize("qtd_equipe,adicional_esperado", [ + (1, 500), + (5, 500), + (6, 1000), + (10, 1000), + (11, 2000), + (15, 2000), +]) +def test_adicional_por_tamanho_equipe(gerente, qtd_equipe, adicional_esperado): + gerente.qtd_equipe = qtd_equipe + assert gerente.calcular_adicionais() == adicional_esperado + +# ---- Teste integrado para equipe de 8 pessoas ---- +def test_salario_liquido_equipe_8(gerente): + gerente.qtd_equipe = 8 + # bonus 15% = 1200, adicional = 1000, desconto 12% = 960 + esperado = 8000 + 1200 + 1000 - 960 # 9240 assert gerente.calcular_salario_liquido() == esperado \ No newline at end of file From 84ed2f786a03e9db3f05b1ab411f5eeba5529293 Mon Sep 17 00:00:00 2001 From: serelepe Date: Sat, 30 May 2026 14:24:25 -0300 Subject: [PATCH 05/12] add Guia3 --- Guia3/.gitignore | 13 + Guia3/README.md | 252 ++++++++++++++++++++ Guia3/main.py | 8 + Guia3/pytest.ini | 3 + Guia3/requirements.txt | 2 + Guia3/src/__init__.py | 9 + Guia3/src/alternativa.py | 4 + Guia3/src/pergunta.py | 4 + Guia3/src/perguntadiscursiva.py | 4 + Guia3/src/perguntamultiplaescolha.py | 4 + Guia3/src/questionario.py | 4 + Guia3/src/resposta.py | 4 + Guia3/src/respostadiscursiva.py | 4 + Guia3/src/respostaobjetiva.py | 4 + Guia3/src/tentativaquestionario.py | 4 + Guia3/tests/__init__.py | 0 Guia3/tests/test_alternativa.py | 21 ++ Guia3/tests/test_pergunta.py | 8 + Guia3/tests/test_perguntadiscursiva.py | 39 +++ Guia3/tests/test_perguntamultiplaescolha.py | 51 ++++ Guia3/tests/test_questionario.py | 27 +++ Guia3/tests/test_resposta.py | 8 + Guia3/tests/test_respostadiscursiva.py | 42 ++++ Guia3/tests/test_respostaobjetiva.py | 59 +++++ Guia3/tests/test_tentativaquestionario.py | 90 +++++++ 25 files changed, 668 insertions(+) create mode 100644 Guia3/.gitignore create mode 100644 Guia3/README.md create mode 100644 Guia3/main.py create mode 100644 Guia3/pytest.ini create mode 100644 Guia3/requirements.txt create mode 100644 Guia3/src/__init__.py create mode 100644 Guia3/src/alternativa.py create mode 100644 Guia3/src/pergunta.py create mode 100644 Guia3/src/perguntadiscursiva.py create mode 100644 Guia3/src/perguntamultiplaescolha.py create mode 100644 Guia3/src/questionario.py create mode 100644 Guia3/src/resposta.py create mode 100644 Guia3/src/respostadiscursiva.py create mode 100644 Guia3/src/respostaobjetiva.py create mode 100644 Guia3/src/tentativaquestionario.py create mode 100644 Guia3/tests/__init__.py create mode 100644 Guia3/tests/test_alternativa.py create mode 100644 Guia3/tests/test_pergunta.py create mode 100644 Guia3/tests/test_perguntadiscursiva.py create mode 100644 Guia3/tests/test_perguntamultiplaescolha.py create mode 100644 Guia3/tests/test_questionario.py create mode 100644 Guia3/tests/test_resposta.py create mode 100644 Guia3/tests/test_respostadiscursiva.py create mode 100644 Guia3/tests/test_respostaobjetiva.py create mode 100644 Guia3/tests/test_tentativaquestionario.py diff --git a/Guia3/.gitignore b/Guia3/.gitignore new file mode 100644 index 0000000..4b3bf0c --- /dev/null +++ b/Guia3/.gitignore @@ -0,0 +1,13 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +venv/ +.venv/ +.venv +env/ +.env +.pytest_cache/ +.pytest_cache +.coverage +htmlcov/ diff --git a/Guia3/README.md b/Guia3/README.md new file mode 100644 index 0000000..c6877eb --- /dev/null +++ b/Guia3/README.md @@ -0,0 +1,252 @@ +# Guia 3 — Sistema de Quiz + +## Contexto + +Você faz parte da equipe responsável por desenvolver um **Sistema de Quiz** educativo. + +O sistema deve permitir a criação de quizzes (questionários) com perguntas de múltipla escolha ou discursivas, validação de respostas e cálculo de pontuação. + +O projeto já possui a estrutura de pastas definidas. Sua missão é **implementar/completar** as classes seguindo o **diagrama UML** e as regras abaixo, passando em todos os testes. + +--- + +## Diagrama UML + +```mermaid +classDiagram + direction TB + + class Pergunta { + <> + -String texto + -String? explicacao_geral //Pode ser None + +validar_resposta(resposta) boolean + +get_explicacao() String + +get_tipo() String + } + + class PerguntaMultiplaEscolha { + -List~Alternativa~ alternativas + +validar_resposta(int indice) boolean + +get_alternativa_correta() Alternativa + } + + class PerguntaDiscursiva { + -String? resposta_esperada //Pode ser None + +validar_resposta(String texto) boolean + } + + class Alternativa { + +String texto + +boolean correta + +String? explicacao //Pode ser None + } + + class Resposta { + <> + -Pergunta pergunta + -boolean esta_correta + -float pontuacao_obtida + +calcular_pontuacao() float + } + + class RespostaObjetiva { + -int indice_escolhido + -Alternativa? alternativa_selecionada //Pode ser None + } + + class RespostaDiscursiva { + -String texto_resposta + } + + class Questionario { + -String titulo + -List~Pergunta~ perguntas + +adicionar_pergunta(Pergunta p) + +criar_attempt(String usuario) QuizAttempt + } + + class TentativaQuestionario { + -Questionario questionario + -String usuario + -DateTime? data_inicio //Pode ser None + -DateTime? data_fim //Pode ser None + -List~Resposta~ respostas + +registrar_resposta(int indice_pergunta, Object valor) + +finalizar() Tuple~float, String~ + +calcular_pontuacao() float + +is_finalizado() boolean + } + + %% Relacionamentos + Pergunta <|-- PerguntaMultiplaEscolha + Pergunta <|-- PerguntaDiscursiva + Resposta <|-- RespostaObjetiva + Resposta <|-- RespostaDiscursiva + + PerguntaMultiplaEscolha "1" *-- "2..*" Alternativa + Questionario "1" *-- "0..*" Pergunta + Questionario "1" --> "0..*" TentativaQuestionario + TentativaQuestionario "1" *-- "0..*" Resposta + Resposta "1" --> "1" Pergunta +``` + +--- + +## Descrição das Classes + +### Pergunta (Classe Abstrata) + +Classe base para todas as perguntas do sistema. + +Atributos: +- texto: String — Enunciado da pergunta. +- explicacao_geral: String? (opcional) — Texto explicativo mostrado após a correção. + +Métodos: +- validar_resposta(resposta) → boolean — Valida a resposta (implementado nas subclasses). +- get_explicacao() → String — Retorna a explicação geral. +- get_tipo() → String — Retorna o tipo ("multipla_escolha" ou "discursiva"). + +### PerguntaMultiplaEscolha + +Herda de Pergunta. Perguntas com alternativas. + +Atributos: +- alternativas: List[Alternativa] — Lista de alternativas. + +Métodos: +- validar_resposta(int indice) → boolean — Valida o índice escolhido. +- get_alternativa_correta() → Alternativa — Retorna a alternativa correta. + +### PerguntaDiscursiva + +Herda de Pergunta. Perguntas com resposta em texto livre. + +Atributos: +- resposta_esperada: String? (opcional) — Resposta considerada correta. +- case_sensitive: boolean — Diferencia maiúsculas/minúsculas. + +Métodos: +- validar_resposta(String texto) → boolean — Compara texto do usuário. + +### Alternativa + +Representa uma opção em perguntas de múltipla escolha. + +Atributos: +- texto: String — Texto da alternativa. +- correta: boolean — Indica se é correta. +- explicacao: String? (opcional) — Explicação da alternativa. + +### Resposta (Classe Abstrata) + +Classe base para respostas dadas pelo usuário. + +Atributos: +- pergunta: Pergunta — Pergunta respondida. +- esta_correta: boolean — Se a resposta está correta. +- pontuacao_obtida: float — Pontuação obtida. + +Métodos: +- calcular_pontuacao() → float — Calcula pontuação. + +### RespostaObjetiva + +Herda de Resposta. Para perguntas de múltipla escolha. + +Atributos: +- indice_escolhido: int — Índice escolhido. +- alternativa_selecionada: Alternativa? (opcional) + +### RespostaDiscursiva + +Herda de Resposta. Para perguntas discursivas. + +Atributos: +- texto_resposta: String — Texto digitado pelo usuário. + +### Quiz + +Modelo/template do quiz (criado uma vez). + +Atributos: +- titulo: String — Título do quiz. +- perguntas: List[Pergunta] — Lista de perguntas. + +Métodos: +- adicionar_pergunta(Pergunta p) +- criar_attempt(String usuario) → QuizAttempt + +### QuizAttempt + +Representa uma tentativa de responder o quiz. + +Atributos: +- quiz: Quiz — Quiz original. +- usuario: String — Usuário. +- data_inicio: DateTime? +- data_fim: DateTime? +- respostas: List[Resposta] + +Métodos: +- registrar_resposta(int indice_pergunta, Object valor) +- finalizar() → (float, String) +- calcular_pontuacao() → float +- is_finalizado() → boolean + +--- + +## Como prepara o ambiente e rodar os testes? + +#### 1. Criar ambiente virutal + +Na pasta do projeto ..\Guia3> executar o comando: + +```bash +python -m venv .venv +``` + +#### 2. Ativar Ambiente Virtual + +Isso garante que qualquer modificação precise ser feita, seja realizada em um Ambiente Virtual controlado e não produza conflitos entre pacotes de outros projetos. + +PowerShell do Windows: +```bash +.\.venv\Scripts\activate +``` +macOS / Linux: +```bash +source .venv/bin/activate +``` +#### 3. Instalar dependências + +Na pasta do projeto ..\Guia3> executar o comando: + +```bash +pip install -r requirements.txt +``` + +#### Rodar exemplo + +Na pasta do projeto ..\Guia3> executar o comando: + +```bash +python main.py +``` + +#### Rodar testes + +Na pasta do projeto ..\Guia3> executar o comando: + +bash +``` +pytest -v +``` + +ou + +bash +``` +python -m pytest -v +``` \ No newline at end of file diff --git a/Guia3/main.py b/Guia3/main.py new file mode 100644 index 0000000..e9e667d --- /dev/null +++ b/Guia3/main.py @@ -0,0 +1,8 @@ +from Guia3.src import * + +def main(): + pass + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Guia3/pytest.ini b/Guia3/pytest.ini new file mode 100644 index 0000000..97a0030 --- /dev/null +++ b/Guia3/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +pythonpath = src +testpaths = tests \ No newline at end of file diff --git a/Guia3/requirements.txt b/Guia3/requirements.txt new file mode 100644 index 0000000..b820918 --- /dev/null +++ b/Guia3/requirements.txt @@ -0,0 +1,2 @@ +pytest>=8.0.0 +pytest-cov>=4.0.0 diff --git a/Guia3/src/__init__.py b/Guia3/src/__init__.py new file mode 100644 index 0000000..9283af9 --- /dev/null +++ b/Guia3/src/__init__.py @@ -0,0 +1,9 @@ +from .alternativa import Alternativa +from .pergunta import Pergunta +from .perguntadiscursiva import PerguntaDiscursiva +from .perguntamultiplaescolha import PerguntaMultiplaEscolha +from .questionario import Questionario +from .resposta import Resposta +from .respostadiscursiva import RespostaDiscursiva +from .respostaobjetiva import RespostaObjetiva +from .tentativaquestionario import TentativaQuestionario \ No newline at end of file diff --git a/Guia3/src/alternativa.py b/Guia3/src/alternativa.py new file mode 100644 index 0000000..4dde61f --- /dev/null +++ b/Guia3/src/alternativa.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class Alternativa: + pass \ No newline at end of file diff --git a/Guia3/src/pergunta.py b/Guia3/src/pergunta.py new file mode 100644 index 0000000..5b3763d --- /dev/null +++ b/Guia3/src/pergunta.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class Pergunta: + pass \ No newline at end of file diff --git a/Guia3/src/perguntadiscursiva.py b/Guia3/src/perguntadiscursiva.py new file mode 100644 index 0000000..f4c26af --- /dev/null +++ b/Guia3/src/perguntadiscursiva.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class PerguntaDiscursiva: + pass \ No newline at end of file diff --git a/Guia3/src/perguntamultiplaescolha.py b/Guia3/src/perguntamultiplaescolha.py new file mode 100644 index 0000000..bcbe94d --- /dev/null +++ b/Guia3/src/perguntamultiplaescolha.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class PerguntaMultiplaEscolha: + pass \ No newline at end of file diff --git a/Guia3/src/questionario.py b/Guia3/src/questionario.py new file mode 100644 index 0000000..7525582 --- /dev/null +++ b/Guia3/src/questionario.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class Questionario: + pass diff --git a/Guia3/src/resposta.py b/Guia3/src/resposta.py new file mode 100644 index 0000000..846d771 --- /dev/null +++ b/Guia3/src/resposta.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class Resposta: + pass \ No newline at end of file diff --git a/Guia3/src/respostadiscursiva.py b/Guia3/src/respostadiscursiva.py new file mode 100644 index 0000000..4ea6dbb --- /dev/null +++ b/Guia3/src/respostadiscursiva.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class RespostaDiscursiva: + pass \ No newline at end of file diff --git a/Guia3/src/respostaobjetiva.py b/Guia3/src/respostaobjetiva.py new file mode 100644 index 0000000..72ed2d0 --- /dev/null +++ b/Guia3/src/respostaobjetiva.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class RespostaObjetiva: + pass \ No newline at end of file diff --git a/Guia3/src/tentativaquestionario.py b/Guia3/src/tentativaquestionario.py new file mode 100644 index 0000000..9947dd1 --- /dev/null +++ b/Guia3/src/tentativaquestionario.py @@ -0,0 +1,4 @@ +from typing import List, Tuple, Dict + +class TentativaQuestionario: + pass \ No newline at end of file diff --git a/Guia3/tests/__init__.py b/Guia3/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Guia3/tests/test_alternativa.py b/Guia3/tests/test_alternativa.py new file mode 100644 index 0000000..41b5c6d --- /dev/null +++ b/Guia3/tests/test_alternativa.py @@ -0,0 +1,21 @@ +import pytest + +from src.alternativa import Alternativa + + +def test_criar_alternativa(): + alt = Alternativa( + texto="Python", + correta=True, + explicacao="Linguagem interpretada" + ) + + assert alt.texto == "Python" + assert alt.correta is True + assert alt.explicacao == "Linguagem interpretada" + + +def test_alternativa_sem_explicacao(): + alt = Alternativa("Java", False) + + assert alt.explicacao is None \ No newline at end of file diff --git a/Guia3/tests/test_pergunta.py b/Guia3/tests/test_pergunta.py new file mode 100644 index 0000000..160c4db --- /dev/null +++ b/Guia3/tests/test_pergunta.py @@ -0,0 +1,8 @@ +import pytest + +from src.pergunta import Pergunta + + +def test_nao_instanciar_pergunta_abstract(): + with pytest.raises(TypeError): + Pergunta("Pergunta abstrata") \ No newline at end of file diff --git a/Guia3/tests/test_perguntadiscursiva.py b/Guia3/tests/test_perguntadiscursiva.py new file mode 100644 index 0000000..04505a7 --- /dev/null +++ b/Guia3/tests/test_perguntadiscursiva.py @@ -0,0 +1,39 @@ +from src.perguntadiscursiva import PerguntaDiscursiva + + +def test_validar_resposta_correta(): + pergunta = PerguntaDiscursiva( + texto="O que é POO?", + resposta_esperada="Programação Orientada a Objetos" + ) + + resposta = "Programação Orientada a Objetos" + + assert pergunta.validar_resposta(resposta) is True + + +def test_validar_resposta_errada(): + pergunta = PerguntaDiscursiva( + texto="O que é POO?", + resposta_esperada="Programação Orientada a Objetos" + ) + + resposta = "Banco de dados" + + assert pergunta.validar_resposta(resposta) is False + + +def test_pergunta_sem_resposta_esperada(): + pergunta = PerguntaDiscursiva( + texto="Explique encapsulamento." + ) + + assert pergunta.resposta_esperada is None + + +def test_get_tipo(): + pergunta = PerguntaDiscursiva( + texto="Explique herança." + ) + + assert pergunta.get_tipo() == "discursiva" \ No newline at end of file diff --git a/Guia3/tests/test_perguntamultiplaescolha.py b/Guia3/tests/test_perguntamultiplaescolha.py new file mode 100644 index 0000000..45f3d32 --- /dev/null +++ b/Guia3/tests/test_perguntamultiplaescolha.py @@ -0,0 +1,51 @@ +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha + + +def criar_pergunta(): + alternativas = [ + Alternativa("Java", False), + Alternativa("Python", True), + Alternativa("C", False), + ] + + return PerguntaMultiplaEscolha( + texto="Qual linguagem é interpretada?", + alternativas=alternativas, + explicacao_geral="Python normalmente é interpretada." + ) + + +def test_validar_resposta_correta(): + pergunta = criar_pergunta() + + assert pergunta.validar_resposta(1) is True + + +def test_validar_resposta_errada(): + pergunta = criar_pergunta() + + assert pergunta.validar_resposta(0) is False + + +def test_get_alternativa_correta(): + pergunta = criar_pergunta() + + correta = pergunta.get_alternativa_correta() + + assert correta.texto == "Python" + assert correta.correta is True + + +def test_get_tipo(): + pergunta = criar_pergunta() + + assert pergunta.get_tipo() == "multipla_escolha" + + +def test_get_explicacao(): + pergunta = criar_pergunta() + + assert pergunta.get_explicacao() == ( + "Python normalmente é interpretada." + ) \ No newline at end of file diff --git a/Guia3/tests/test_questionario.py b/Guia3/tests/test_questionario.py new file mode 100644 index 0000000..c592025 --- /dev/null +++ b/Guia3/tests/test_questionario.py @@ -0,0 +1,27 @@ +import pytest + +from src.questionario import Questionario +from src.perguntadiscursiva import PerguntaDiscursiva +from src.tentativaquestionario import TentativaQuestionario + + +def test_adicionar_pergunta(): + questionario = Questionario("Quiz POO") + + pergunta = PerguntaDiscursiva( + texto="O que é encapsulamento?" + ) + + questionario.adicionar_pergunta(pergunta) + + assert len(questionario.perguntas) == 1 + + +def test_criar_attempt(): + questionario = Questionario("Quiz Redes") + + tentativa = questionario.criar_attempt("valter") + + assert isinstance(tentativa, TentativaQuestionario) + assert tentativa.usuario == "valter" + diff --git a/Guia3/tests/test_resposta.py b/Guia3/tests/test_resposta.py new file mode 100644 index 0000000..fd9a6d6 --- /dev/null +++ b/Guia3/tests/test_resposta.py @@ -0,0 +1,8 @@ +import pytest + +from src.resposta import Resposta + + +def test_nao_instanciar_resposta_abstract(): + with pytest.raises(TypeError): + Resposta(None) \ No newline at end of file diff --git a/Guia3/tests/test_respostadiscursiva.py b/Guia3/tests/test_respostadiscursiva.py new file mode 100644 index 0000000..b1201d4 --- /dev/null +++ b/Guia3/tests/test_respostadiscursiva.py @@ -0,0 +1,42 @@ +from src.perguntadiscursiva import PerguntaDiscursiva +from src.respostadiscursiva import RespostaDiscursiva + + +def criar_pergunta(): + return PerguntaDiscursiva( + texto="O que significa CPU?", + resposta_esperada="Central Processing Unit" + ) + + +def test_resposta_discursiva_correta(): + pergunta = criar_pergunta() + + resposta = RespostaDiscursiva( + pergunta=pergunta, + texto_resposta="Central Processing Unit" + ) + + assert resposta.esta_correta is True + + +def test_resposta_discursiva_errada(): + pergunta = criar_pergunta() + + resposta = RespostaDiscursiva( + pergunta=pergunta, + texto_resposta="Memória RAM" + ) + + assert resposta.esta_correta is False + + +def test_calcular_pontuacao(): + pergunta = criar_pergunta() + + resposta = RespostaDiscursiva( + pergunta=pergunta, + texto_resposta="Central Processing Unit" + ) + + assert resposta.calcular_pontuacao() == 1.0 \ No newline at end of file diff --git a/Guia3/tests/test_respostaobjetiva.py b/Guia3/tests/test_respostaobjetiva.py new file mode 100644 index 0000000..e2a0739 --- /dev/null +++ b/Guia3/tests/test_respostaobjetiva.py @@ -0,0 +1,59 @@ +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.respostaobjetiva import RespostaObjetiva + + +def criar_pergunta(): + alternativas = [ + Alternativa("HTTP", False), + Alternativa("TCP/IP", True), + ] + + return PerguntaMultiplaEscolha( + texto="Qual protocolo é base da internet?", + alternativas=alternativas + ) + + +def test_resposta_objetiva_correta(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=1 + ) + + assert resposta.esta_correta is True + + +def test_resposta_objetiva_errada(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=0 + ) + + assert resposta.esta_correta is False + + +def test_calcular_pontuacao_correta(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=1 + ) + + assert resposta.calcular_pontuacao() == 1.0 + + +def test_calcular_pontuacao_errada(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=0 + ) + + assert resposta.calcular_pontuacao() == 0.0 \ No newline at end of file diff --git a/Guia3/tests/test_tentativaquestionario.py b/Guia3/tests/test_tentativaquestionario.py new file mode 100644 index 0000000..e0f4ede --- /dev/null +++ b/Guia3/tests/test_tentativaquestionario.py @@ -0,0 +1,90 @@ +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.perguntadiscursiva import PerguntaDiscursiva +from src.questionario import Questionario +from src.tentativaquestionario import TentativaQuestionario + + +def criar_questionario(): + q = Questionario("Quiz") + + p1 = PerguntaMultiplaEscolha( + texto="2 + 2?", + alternativas=[ + Alternativa("3", False), + Alternativa("4", True), + ] + ) + + p2 = PerguntaDiscursiva( + texto="Sigla CPU", + resposta_esperada="Central Processing Unit" + ) + + q.adicionar_pergunta(p1) + q.adicionar_pergunta(p2) + + return q + + +def test_registrar_resposta_objetiva(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta(0, 1) + + assert len(tentativa.respostas) == 1 + + +def test_registrar_resposta_discursiva(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta( + 1, + "Central Processing Unit" + ) + + assert len(tentativa.respostas) == 1 + + +def test_calcular_pontuacao(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta(0, 1) + tentativa.registrar_resposta( + 1, + "Central Processing Unit" + ) + + assert tentativa.calcular_pontuacao() == 2.0 + + +def test_finalizar(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta(0, 1) + + pontuacao, feedback = tentativa.finalizar() + + assert pontuacao >= 0 + assert isinstance(feedback, str) + assert tentativa.is_finalizado() is True \ No newline at end of file From 6e5eb04053cbb5e0778698ec4eb559425a5dc6c4 Mon Sep 17 00:00:00 2001 From: serelepe Date: Sat, 6 Jun 2026 21:31:57 -0300 Subject: [PATCH 06/12] Removendo g3 --- Guia3/.gitignore | 13 - Guia3/README.md | 252 -------------------- Guia3/main.py | 8 - Guia3/pytest.ini | 3 - Guia3/requirements.txt | 2 - Guia3/src/__init__.py | 9 - Guia3/src/alternativa.py | 4 - Guia3/src/pergunta.py | 4 - Guia3/src/perguntadiscursiva.py | 4 - Guia3/src/perguntamultiplaescolha.py | 4 - Guia3/src/questionario.py | 4 - Guia3/src/resposta.py | 4 - Guia3/src/respostadiscursiva.py | 4 - Guia3/src/respostaobjetiva.py | 4 - Guia3/src/tentativaquestionario.py | 4 - Guia3/tests/__init__.py | 0 Guia3/tests/test_alternativa.py | 21 -- Guia3/tests/test_pergunta.py | 8 - Guia3/tests/test_perguntadiscursiva.py | 39 --- Guia3/tests/test_perguntamultiplaescolha.py | 51 ---- Guia3/tests/test_questionario.py | 27 --- Guia3/tests/test_resposta.py | 8 - Guia3/tests/test_respostadiscursiva.py | 42 ---- Guia3/tests/test_respostaobjetiva.py | 59 ----- Guia3/tests/test_tentativaquestionario.py | 90 ------- 25 files changed, 668 deletions(-) delete mode 100644 Guia3/.gitignore delete mode 100644 Guia3/README.md delete mode 100644 Guia3/main.py delete mode 100644 Guia3/pytest.ini delete mode 100644 Guia3/requirements.txt delete mode 100644 Guia3/src/__init__.py delete mode 100644 Guia3/src/alternativa.py delete mode 100644 Guia3/src/pergunta.py delete mode 100644 Guia3/src/perguntadiscursiva.py delete mode 100644 Guia3/src/perguntamultiplaescolha.py delete mode 100644 Guia3/src/questionario.py delete mode 100644 Guia3/src/resposta.py delete mode 100644 Guia3/src/respostadiscursiva.py delete mode 100644 Guia3/src/respostaobjetiva.py delete mode 100644 Guia3/src/tentativaquestionario.py delete mode 100644 Guia3/tests/__init__.py delete mode 100644 Guia3/tests/test_alternativa.py delete mode 100644 Guia3/tests/test_pergunta.py delete mode 100644 Guia3/tests/test_perguntadiscursiva.py delete mode 100644 Guia3/tests/test_perguntamultiplaescolha.py delete mode 100644 Guia3/tests/test_questionario.py delete mode 100644 Guia3/tests/test_resposta.py delete mode 100644 Guia3/tests/test_respostadiscursiva.py delete mode 100644 Guia3/tests/test_respostaobjetiva.py delete mode 100644 Guia3/tests/test_tentativaquestionario.py diff --git a/Guia3/.gitignore b/Guia3/.gitignore deleted file mode 100644 index 4b3bf0c..0000000 --- a/Guia3/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -__pycache__/ -*.pyc -*.pyo -*.pyd -venv/ -.venv/ -.venv -env/ -.env -.pytest_cache/ -.pytest_cache -.coverage -htmlcov/ diff --git a/Guia3/README.md b/Guia3/README.md deleted file mode 100644 index c6877eb..0000000 --- a/Guia3/README.md +++ /dev/null @@ -1,252 +0,0 @@ -# Guia 3 — Sistema de Quiz - -## Contexto - -Você faz parte da equipe responsável por desenvolver um **Sistema de Quiz** educativo. - -O sistema deve permitir a criação de quizzes (questionários) com perguntas de múltipla escolha ou discursivas, validação de respostas e cálculo de pontuação. - -O projeto já possui a estrutura de pastas definidas. Sua missão é **implementar/completar** as classes seguindo o **diagrama UML** e as regras abaixo, passando em todos os testes. - ---- - -## Diagrama UML - -```mermaid -classDiagram - direction TB - - class Pergunta { - <> - -String texto - -String? explicacao_geral //Pode ser None - +validar_resposta(resposta) boolean - +get_explicacao() String - +get_tipo() String - } - - class PerguntaMultiplaEscolha { - -List~Alternativa~ alternativas - +validar_resposta(int indice) boolean - +get_alternativa_correta() Alternativa - } - - class PerguntaDiscursiva { - -String? resposta_esperada //Pode ser None - +validar_resposta(String texto) boolean - } - - class Alternativa { - +String texto - +boolean correta - +String? explicacao //Pode ser None - } - - class Resposta { - <> - -Pergunta pergunta - -boolean esta_correta - -float pontuacao_obtida - +calcular_pontuacao() float - } - - class RespostaObjetiva { - -int indice_escolhido - -Alternativa? alternativa_selecionada //Pode ser None - } - - class RespostaDiscursiva { - -String texto_resposta - } - - class Questionario { - -String titulo - -List~Pergunta~ perguntas - +adicionar_pergunta(Pergunta p) - +criar_attempt(String usuario) QuizAttempt - } - - class TentativaQuestionario { - -Questionario questionario - -String usuario - -DateTime? data_inicio //Pode ser None - -DateTime? data_fim //Pode ser None - -List~Resposta~ respostas - +registrar_resposta(int indice_pergunta, Object valor) - +finalizar() Tuple~float, String~ - +calcular_pontuacao() float - +is_finalizado() boolean - } - - %% Relacionamentos - Pergunta <|-- PerguntaMultiplaEscolha - Pergunta <|-- PerguntaDiscursiva - Resposta <|-- RespostaObjetiva - Resposta <|-- RespostaDiscursiva - - PerguntaMultiplaEscolha "1" *-- "2..*" Alternativa - Questionario "1" *-- "0..*" Pergunta - Questionario "1" --> "0..*" TentativaQuestionario - TentativaQuestionario "1" *-- "0..*" Resposta - Resposta "1" --> "1" Pergunta -``` - ---- - -## Descrição das Classes - -### Pergunta (Classe Abstrata) - -Classe base para todas as perguntas do sistema. - -Atributos: -- texto: String — Enunciado da pergunta. -- explicacao_geral: String? (opcional) — Texto explicativo mostrado após a correção. - -Métodos: -- validar_resposta(resposta) → boolean — Valida a resposta (implementado nas subclasses). -- get_explicacao() → String — Retorna a explicação geral. -- get_tipo() → String — Retorna o tipo ("multipla_escolha" ou "discursiva"). - -### PerguntaMultiplaEscolha - -Herda de Pergunta. Perguntas com alternativas. - -Atributos: -- alternativas: List[Alternativa] — Lista de alternativas. - -Métodos: -- validar_resposta(int indice) → boolean — Valida o índice escolhido. -- get_alternativa_correta() → Alternativa — Retorna a alternativa correta. - -### PerguntaDiscursiva - -Herda de Pergunta. Perguntas com resposta em texto livre. - -Atributos: -- resposta_esperada: String? (opcional) — Resposta considerada correta. -- case_sensitive: boolean — Diferencia maiúsculas/minúsculas. - -Métodos: -- validar_resposta(String texto) → boolean — Compara texto do usuário. - -### Alternativa - -Representa uma opção em perguntas de múltipla escolha. - -Atributos: -- texto: String — Texto da alternativa. -- correta: boolean — Indica se é correta. -- explicacao: String? (opcional) — Explicação da alternativa. - -### Resposta (Classe Abstrata) - -Classe base para respostas dadas pelo usuário. - -Atributos: -- pergunta: Pergunta — Pergunta respondida. -- esta_correta: boolean — Se a resposta está correta. -- pontuacao_obtida: float — Pontuação obtida. - -Métodos: -- calcular_pontuacao() → float — Calcula pontuação. - -### RespostaObjetiva - -Herda de Resposta. Para perguntas de múltipla escolha. - -Atributos: -- indice_escolhido: int — Índice escolhido. -- alternativa_selecionada: Alternativa? (opcional) - -### RespostaDiscursiva - -Herda de Resposta. Para perguntas discursivas. - -Atributos: -- texto_resposta: String — Texto digitado pelo usuário. - -### Quiz - -Modelo/template do quiz (criado uma vez). - -Atributos: -- titulo: String — Título do quiz. -- perguntas: List[Pergunta] — Lista de perguntas. - -Métodos: -- adicionar_pergunta(Pergunta p) -- criar_attempt(String usuario) → QuizAttempt - -### QuizAttempt - -Representa uma tentativa de responder o quiz. - -Atributos: -- quiz: Quiz — Quiz original. -- usuario: String — Usuário. -- data_inicio: DateTime? -- data_fim: DateTime? -- respostas: List[Resposta] - -Métodos: -- registrar_resposta(int indice_pergunta, Object valor) -- finalizar() → (float, String) -- calcular_pontuacao() → float -- is_finalizado() → boolean - ---- - -## Como prepara o ambiente e rodar os testes? - -#### 1. Criar ambiente virutal - -Na pasta do projeto ..\Guia3> executar o comando: - -```bash -python -m venv .venv -``` - -#### 2. Ativar Ambiente Virtual - -Isso garante que qualquer modificação precise ser feita, seja realizada em um Ambiente Virtual controlado e não produza conflitos entre pacotes de outros projetos. - -PowerShell do Windows: -```bash -.\.venv\Scripts\activate -``` -macOS / Linux: -```bash -source .venv/bin/activate -``` -#### 3. Instalar dependências - -Na pasta do projeto ..\Guia3> executar o comando: - -```bash -pip install -r requirements.txt -``` - -#### Rodar exemplo - -Na pasta do projeto ..\Guia3> executar o comando: - -```bash -python main.py -``` - -#### Rodar testes - -Na pasta do projeto ..\Guia3> executar o comando: - -bash -``` -pytest -v -``` - -ou - -bash -``` -python -m pytest -v -``` \ No newline at end of file diff --git a/Guia3/main.py b/Guia3/main.py deleted file mode 100644 index e9e667d..0000000 --- a/Guia3/main.py +++ /dev/null @@ -1,8 +0,0 @@ -from Guia3.src import * - -def main(): - pass - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/Guia3/pytest.ini b/Guia3/pytest.ini deleted file mode 100644 index 97a0030..0000000 --- a/Guia3/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -pythonpath = src -testpaths = tests \ No newline at end of file diff --git a/Guia3/requirements.txt b/Guia3/requirements.txt deleted file mode 100644 index b820918..0000000 --- a/Guia3/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest>=8.0.0 -pytest-cov>=4.0.0 diff --git a/Guia3/src/__init__.py b/Guia3/src/__init__.py deleted file mode 100644 index 9283af9..0000000 --- a/Guia3/src/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from .alternativa import Alternativa -from .pergunta import Pergunta -from .perguntadiscursiva import PerguntaDiscursiva -from .perguntamultiplaescolha import PerguntaMultiplaEscolha -from .questionario import Questionario -from .resposta import Resposta -from .respostadiscursiva import RespostaDiscursiva -from .respostaobjetiva import RespostaObjetiva -from .tentativaquestionario import TentativaQuestionario \ No newline at end of file diff --git a/Guia3/src/alternativa.py b/Guia3/src/alternativa.py deleted file mode 100644 index 4dde61f..0000000 --- a/Guia3/src/alternativa.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class Alternativa: - pass \ No newline at end of file diff --git a/Guia3/src/pergunta.py b/Guia3/src/pergunta.py deleted file mode 100644 index 5b3763d..0000000 --- a/Guia3/src/pergunta.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class Pergunta: - pass \ No newline at end of file diff --git a/Guia3/src/perguntadiscursiva.py b/Guia3/src/perguntadiscursiva.py deleted file mode 100644 index f4c26af..0000000 --- a/Guia3/src/perguntadiscursiva.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class PerguntaDiscursiva: - pass \ No newline at end of file diff --git a/Guia3/src/perguntamultiplaescolha.py b/Guia3/src/perguntamultiplaescolha.py deleted file mode 100644 index bcbe94d..0000000 --- a/Guia3/src/perguntamultiplaescolha.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class PerguntaMultiplaEscolha: - pass \ No newline at end of file diff --git a/Guia3/src/questionario.py b/Guia3/src/questionario.py deleted file mode 100644 index 7525582..0000000 --- a/Guia3/src/questionario.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class Questionario: - pass diff --git a/Guia3/src/resposta.py b/Guia3/src/resposta.py deleted file mode 100644 index 846d771..0000000 --- a/Guia3/src/resposta.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class Resposta: - pass \ No newline at end of file diff --git a/Guia3/src/respostadiscursiva.py b/Guia3/src/respostadiscursiva.py deleted file mode 100644 index 4ea6dbb..0000000 --- a/Guia3/src/respostadiscursiva.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class RespostaDiscursiva: - pass \ No newline at end of file diff --git a/Guia3/src/respostaobjetiva.py b/Guia3/src/respostaobjetiva.py deleted file mode 100644 index 72ed2d0..0000000 --- a/Guia3/src/respostaobjetiva.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class RespostaObjetiva: - pass \ No newline at end of file diff --git a/Guia3/src/tentativaquestionario.py b/Guia3/src/tentativaquestionario.py deleted file mode 100644 index 9947dd1..0000000 --- a/Guia3/src/tentativaquestionario.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List, Tuple, Dict - -class TentativaQuestionario: - pass \ No newline at end of file diff --git a/Guia3/tests/__init__.py b/Guia3/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Guia3/tests/test_alternativa.py b/Guia3/tests/test_alternativa.py deleted file mode 100644 index 41b5c6d..0000000 --- a/Guia3/tests/test_alternativa.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - -from src.alternativa import Alternativa - - -def test_criar_alternativa(): - alt = Alternativa( - texto="Python", - correta=True, - explicacao="Linguagem interpretada" - ) - - assert alt.texto == "Python" - assert alt.correta is True - assert alt.explicacao == "Linguagem interpretada" - - -def test_alternativa_sem_explicacao(): - alt = Alternativa("Java", False) - - assert alt.explicacao is None \ No newline at end of file diff --git a/Guia3/tests/test_pergunta.py b/Guia3/tests/test_pergunta.py deleted file mode 100644 index 160c4db..0000000 --- a/Guia3/tests/test_pergunta.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest - -from src.pergunta import Pergunta - - -def test_nao_instanciar_pergunta_abstract(): - with pytest.raises(TypeError): - Pergunta("Pergunta abstrata") \ No newline at end of file diff --git a/Guia3/tests/test_perguntadiscursiva.py b/Guia3/tests/test_perguntadiscursiva.py deleted file mode 100644 index 04505a7..0000000 --- a/Guia3/tests/test_perguntadiscursiva.py +++ /dev/null @@ -1,39 +0,0 @@ -from src.perguntadiscursiva import PerguntaDiscursiva - - -def test_validar_resposta_correta(): - pergunta = PerguntaDiscursiva( - texto="O que é POO?", - resposta_esperada="Programação Orientada a Objetos" - ) - - resposta = "Programação Orientada a Objetos" - - assert pergunta.validar_resposta(resposta) is True - - -def test_validar_resposta_errada(): - pergunta = PerguntaDiscursiva( - texto="O que é POO?", - resposta_esperada="Programação Orientada a Objetos" - ) - - resposta = "Banco de dados" - - assert pergunta.validar_resposta(resposta) is False - - -def test_pergunta_sem_resposta_esperada(): - pergunta = PerguntaDiscursiva( - texto="Explique encapsulamento." - ) - - assert pergunta.resposta_esperada is None - - -def test_get_tipo(): - pergunta = PerguntaDiscursiva( - texto="Explique herança." - ) - - assert pergunta.get_tipo() == "discursiva" \ No newline at end of file diff --git a/Guia3/tests/test_perguntamultiplaescolha.py b/Guia3/tests/test_perguntamultiplaescolha.py deleted file mode 100644 index 45f3d32..0000000 --- a/Guia3/tests/test_perguntamultiplaescolha.py +++ /dev/null @@ -1,51 +0,0 @@ -from src.alternativa import Alternativa -from src.perguntamultiplaescolha import PerguntaMultiplaEscolha - - -def criar_pergunta(): - alternativas = [ - Alternativa("Java", False), - Alternativa("Python", True), - Alternativa("C", False), - ] - - return PerguntaMultiplaEscolha( - texto="Qual linguagem é interpretada?", - alternativas=alternativas, - explicacao_geral="Python normalmente é interpretada." - ) - - -def test_validar_resposta_correta(): - pergunta = criar_pergunta() - - assert pergunta.validar_resposta(1) is True - - -def test_validar_resposta_errada(): - pergunta = criar_pergunta() - - assert pergunta.validar_resposta(0) is False - - -def test_get_alternativa_correta(): - pergunta = criar_pergunta() - - correta = pergunta.get_alternativa_correta() - - assert correta.texto == "Python" - assert correta.correta is True - - -def test_get_tipo(): - pergunta = criar_pergunta() - - assert pergunta.get_tipo() == "multipla_escolha" - - -def test_get_explicacao(): - pergunta = criar_pergunta() - - assert pergunta.get_explicacao() == ( - "Python normalmente é interpretada." - ) \ No newline at end of file diff --git a/Guia3/tests/test_questionario.py b/Guia3/tests/test_questionario.py deleted file mode 100644 index c592025..0000000 --- a/Guia3/tests/test_questionario.py +++ /dev/null @@ -1,27 +0,0 @@ -import pytest - -from src.questionario import Questionario -from src.perguntadiscursiva import PerguntaDiscursiva -from src.tentativaquestionario import TentativaQuestionario - - -def test_adicionar_pergunta(): - questionario = Questionario("Quiz POO") - - pergunta = PerguntaDiscursiva( - texto="O que é encapsulamento?" - ) - - questionario.adicionar_pergunta(pergunta) - - assert len(questionario.perguntas) == 1 - - -def test_criar_attempt(): - questionario = Questionario("Quiz Redes") - - tentativa = questionario.criar_attempt("valter") - - assert isinstance(tentativa, TentativaQuestionario) - assert tentativa.usuario == "valter" - diff --git a/Guia3/tests/test_resposta.py b/Guia3/tests/test_resposta.py deleted file mode 100644 index fd9a6d6..0000000 --- a/Guia3/tests/test_resposta.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest - -from src.resposta import Resposta - - -def test_nao_instanciar_resposta_abstract(): - with pytest.raises(TypeError): - Resposta(None) \ No newline at end of file diff --git a/Guia3/tests/test_respostadiscursiva.py b/Guia3/tests/test_respostadiscursiva.py deleted file mode 100644 index b1201d4..0000000 --- a/Guia3/tests/test_respostadiscursiva.py +++ /dev/null @@ -1,42 +0,0 @@ -from src.perguntadiscursiva import PerguntaDiscursiva -from src.respostadiscursiva import RespostaDiscursiva - - -def criar_pergunta(): - return PerguntaDiscursiva( - texto="O que significa CPU?", - resposta_esperada="Central Processing Unit" - ) - - -def test_resposta_discursiva_correta(): - pergunta = criar_pergunta() - - resposta = RespostaDiscursiva( - pergunta=pergunta, - texto_resposta="Central Processing Unit" - ) - - assert resposta.esta_correta is True - - -def test_resposta_discursiva_errada(): - pergunta = criar_pergunta() - - resposta = RespostaDiscursiva( - pergunta=pergunta, - texto_resposta="Memória RAM" - ) - - assert resposta.esta_correta is False - - -def test_calcular_pontuacao(): - pergunta = criar_pergunta() - - resposta = RespostaDiscursiva( - pergunta=pergunta, - texto_resposta="Central Processing Unit" - ) - - assert resposta.calcular_pontuacao() == 1.0 \ No newline at end of file diff --git a/Guia3/tests/test_respostaobjetiva.py b/Guia3/tests/test_respostaobjetiva.py deleted file mode 100644 index e2a0739..0000000 --- a/Guia3/tests/test_respostaobjetiva.py +++ /dev/null @@ -1,59 +0,0 @@ -from src.alternativa import Alternativa -from src.perguntamultiplaescolha import PerguntaMultiplaEscolha -from src.respostaobjetiva import RespostaObjetiva - - -def criar_pergunta(): - alternativas = [ - Alternativa("HTTP", False), - Alternativa("TCP/IP", True), - ] - - return PerguntaMultiplaEscolha( - texto="Qual protocolo é base da internet?", - alternativas=alternativas - ) - - -def test_resposta_objetiva_correta(): - pergunta = criar_pergunta() - - resposta = RespostaObjetiva( - pergunta=pergunta, - indice_escolhido=1 - ) - - assert resposta.esta_correta is True - - -def test_resposta_objetiva_errada(): - pergunta = criar_pergunta() - - resposta = RespostaObjetiva( - pergunta=pergunta, - indice_escolhido=0 - ) - - assert resposta.esta_correta is False - - -def test_calcular_pontuacao_correta(): - pergunta = criar_pergunta() - - resposta = RespostaObjetiva( - pergunta=pergunta, - indice_escolhido=1 - ) - - assert resposta.calcular_pontuacao() == 1.0 - - -def test_calcular_pontuacao_errada(): - pergunta = criar_pergunta() - - resposta = RespostaObjetiva( - pergunta=pergunta, - indice_escolhido=0 - ) - - assert resposta.calcular_pontuacao() == 0.0 \ No newline at end of file diff --git a/Guia3/tests/test_tentativaquestionario.py b/Guia3/tests/test_tentativaquestionario.py deleted file mode 100644 index e0f4ede..0000000 --- a/Guia3/tests/test_tentativaquestionario.py +++ /dev/null @@ -1,90 +0,0 @@ -from src.alternativa import Alternativa -from src.perguntamultiplaescolha import PerguntaMultiplaEscolha -from src.perguntadiscursiva import PerguntaDiscursiva -from src.questionario import Questionario -from src.tentativaquestionario import TentativaQuestionario - - -def criar_questionario(): - q = Questionario("Quiz") - - p1 = PerguntaMultiplaEscolha( - texto="2 + 2?", - alternativas=[ - Alternativa("3", False), - Alternativa("4", True), - ] - ) - - p2 = PerguntaDiscursiva( - texto="Sigla CPU", - resposta_esperada="Central Processing Unit" - ) - - q.adicionar_pergunta(p1) - q.adicionar_pergunta(p2) - - return q - - -def test_registrar_resposta_objetiva(): - q = criar_questionario() - - tentativa = TentativaQuestionario( - questionario=q, - usuario="valter" - ) - - tentativa.registrar_resposta(0, 1) - - assert len(tentativa.respostas) == 1 - - -def test_registrar_resposta_discursiva(): - q = criar_questionario() - - tentativa = TentativaQuestionario( - questionario=q, - usuario="valter" - ) - - tentativa.registrar_resposta( - 1, - "Central Processing Unit" - ) - - assert len(tentativa.respostas) == 1 - - -def test_calcular_pontuacao(): - q = criar_questionario() - - tentativa = TentativaQuestionario( - questionario=q, - usuario="valter" - ) - - tentativa.registrar_resposta(0, 1) - tentativa.registrar_resposta( - 1, - "Central Processing Unit" - ) - - assert tentativa.calcular_pontuacao() == 2.0 - - -def test_finalizar(): - q = criar_questionario() - - tentativa = TentativaQuestionario( - questionario=q, - usuario="valter" - ) - - tentativa.registrar_resposta(0, 1) - - pontuacao, feedback = tentativa.finalizar() - - assert pontuacao >= 0 - assert isinstance(feedback, str) - assert tentativa.is_finalizado() is True \ No newline at end of file From 0de6d8d6c68fec6eafe9e8048be2e62f75c3b994 Mon Sep 17 00:00:00 2001 From: serelepe Date: Mon, 8 Jun 2026 16:48:21 -0300 Subject: [PATCH 07/12] part 1 done --- .../src/__pycache__/__init__.cpython-314.pyc | Bin 146 -> 146 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 153 -> 153 bytes .../__pycache__/settings.cpython-314.pyc | Bin 749 -> 749 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 153 -> 153 bytes .../models/__pycache__/record.cpython-314.pyc | Bin 2355 -> 2355 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 159 -> 159 bytes .../abstract_repository.cpython-314.pyc | Bin 1028 -> 1028 bytes .../record_repository.cpython-314.pyc | Bin 3860 -> 3860 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 155 -> 155 bytes .../record_service.cpython-314.pyc | Bin 1655 -> 1655 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 152 -> 152 bytes .../__pycache__/file_loader.cpython-314.pyc | Bin 1445 -> 1445 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 148 -> 148 bytes .../test_runner.cpython-314-pytest-9.0.3.pyc | Bin 0 -> 5544 bytes Guia3/.gitignore | 13 + Guia3/README.md | 252 ++++++++++++++++++ Guia3/main.py | 9 + Guia3/pytest.ini | 3 + Guia3/requirements.txt | 2 + Guia3/src/__init__.py | 9 + Guia3/src/alternativa.py | 8 + Guia3/src/pergunta.py | 22 ++ Guia3/src/perguntadiscursiva.py | 32 +++ Guia3/src/perguntamultiplaescolha.py | 28 ++ Guia3/src/questionario.py | 23 ++ Guia3/src/resposta.py | 13 + Guia3/src/respostadiscursiva.py | 8 + Guia3/src/respostaobjetiva.py | 17 ++ Guia3/src/tentativaquestionario.py | 26 ++ Guia3/tests/__init__.py | 0 Guia3/tests/test_alternativa.py | 21 ++ Guia3/tests/test_pergunta.py | 8 + Guia3/tests/test_perguntadiscursiva.py | 33 +++ Guia3/tests/test_perguntamultiplaescolha.py | 51 ++++ Guia3/tests/test_questionario.py | 27 ++ Guia3/tests/test_resposta.py | 8 + Guia3/tests/test_respostadiscursiva.py | 42 +++ Guia3/tests/test_respostaobjetiva.py | 59 ++++ Guia3/tests/test_tentativaquestionario.py | 90 +++++++ 39 files changed, 804 insertions(+) create mode 100644 Guia1/tests/__pycache__/test_runner.cpython-314-pytest-9.0.3.pyc create mode 100644 Guia3/.gitignore create mode 100644 Guia3/README.md create mode 100644 Guia3/main.py create mode 100644 Guia3/pytest.ini create mode 100644 Guia3/requirements.txt create mode 100644 Guia3/src/__init__.py create mode 100644 Guia3/src/alternativa.py create mode 100644 Guia3/src/pergunta.py create mode 100644 Guia3/src/perguntadiscursiva.py create mode 100644 Guia3/src/perguntamultiplaescolha.py create mode 100644 Guia3/src/questionario.py create mode 100644 Guia3/src/resposta.py create mode 100644 Guia3/src/respostadiscursiva.py create mode 100644 Guia3/src/respostaobjetiva.py create mode 100644 Guia3/src/tentativaquestionario.py create mode 100644 Guia3/tests/__init__.py create mode 100644 Guia3/tests/test_alternativa.py create mode 100644 Guia3/tests/test_pergunta.py create mode 100644 Guia3/tests/test_perguntadiscursiva.py create mode 100644 Guia3/tests/test_perguntamultiplaescolha.py create mode 100644 Guia3/tests/test_questionario.py create mode 100644 Guia3/tests/test_resposta.py create mode 100644 Guia3/tests/test_respostadiscursiva.py create mode 100644 Guia3/tests/test_respostaobjetiva.py create mode 100644 Guia3/tests/test_tentativaquestionario.py diff --git a/Guia1/src/__pycache__/__init__.cpython-314.pyc b/Guia1/src/__pycache__/__init__.cpython-314.pyc index 72dd53e33571d4ded118fb0800803b0bfd875416..5d0d156839e47721790a4d9e47e5a6d384b5f5e6 100644 GIT binary patch delta 19 ZcmbQlIEj&4n~#@^0SM}Nr6+Q?0{|aw14{q^ delta 19 ZcmbQlIEj&4n~#@^0SF@A3rys02LK|+1N;C0 diff --git a/Guia1/src/config/__pycache__/__init__.cpython-314.pyc b/Guia1/src/config/__pycache__/__init__.cpython-314.pyc index 7e2883e19bd623b47aa8ede8e098cf0b0fd704ee..4603fb070df9b223dd7d9ca16961f5f2b413b8c5 100644 GIT binary patch delta 19 ZcmbQqIFpfEn~#@^0SM}Nr6+Rt0RSLy17H9E delta 19 ZcmbQqIFpfEn~#@^0SF@A3ryth0{|n+1Q7rL diff --git a/Guia1/src/config/__pycache__/settings.cpython-314.pyc b/Guia1/src/config/__pycache__/settings.cpython-314.pyc index 5eeec148bdc5b17a25e5551f2e3d7f4d8477f1c8..2733f408c3470a0b1c46edbb0726a5bfe488dfcf 100644 GIT binary patch delta 20 acmaFM`j(Yjn~#@^0SM}Nr8javVgdj%0tAKt delta 20 acmaFM`j(Yjn~#@^0SF@A3vA?m!~_5~4Fxv< diff --git a/Guia1/src/models/__pycache__/__init__.cpython-314.pyc b/Guia1/src/models/__pycache__/__init__.cpython-314.pyc index 7a7e1ea3ee097de919629c86f9fdacc211bd3332..ba931d560dd4b5e57260eb2f29d23aa1fa499453 100644 GIT binary patch delta 19 ZcmbQqIFpfEn~#@^0SM}Nr6+Rt0RSLy17H9E delta 19 ZcmbQqIFpfEn~#@^0SF@A3ryth0{|n+1Q7rL diff --git a/Guia1/src/models/__pycache__/record.cpython-314.pyc b/Guia1/src/models/__pycache__/record.cpython-314.pyc index 645452895a2a019254486b147ab2c065afab97ad..13b8500a97ab10ee93f139b8cd106e9e5103ab3c 100644 GIT binary patch delta 20 acmdliv{{H-n~#@^0SM}Nr8jbGZ~_1+%>#J= delta 20 acmdliv{{H-n~#@^0SHt-2yEom-~<3Hc?0+W diff --git a/Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc b/Guia1/src/repositories/__pycache__/__init__.cpython-314.pyc index d73b0c8bea37518b169d3686c255dd97a3149374..8afe15f8b4783cb2a446e91210309d6c0ddb4593 100644 GIT binary patch delta 19 ZcmbQwIG>SQn~#@^0SM}Nr6+Pv0RSOR19AWW delta 19 ZcmbQwIG>SQn~#@^0SF@A3rysm0stha1S0?d diff --git a/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc b/Guia1/src/repositories/__pycache__/abstract_repository.cpython-314.pyc index fb28955cb911383858af23722d85d252c89826a4..569f283bb1869eb4aabcb99a0651c2a459cc6785 100644 GIT binary patch delta 20 ZcmZqSXyM@2=HumJ0D?MR>5be!nE@jQ1JVEh delta 20 acmZqSXyM@2=HumJ0D_430vox1G6Mi75(I+) diff --git a/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc b/Guia1/src/repositories/__pycache__/record_repository.cpython-314.pyc index 1dac0c003611addffd9d9af6737b38488c21d006..fdb384c80cf79f34d5a75086e8827f6512765a79 100644 GIT binary patch delta 20 acmbOtH${$Hn~#@^0SM}Nr8jbO@&f=Ss{=X! delta 20 acmbOtH${$Hn~#@^0SMy02yEo$o`s03~R diff --git a/Guia1/tests/__pycache__/__init__.cpython-314.pyc b/Guia1/tests/__pycache__/__init__.cpython-314.pyc index 74b190c76f04268b6b96420064f9e03481ada412..3e0eb136a2c8245271f8d6e84603c83bc909709c 100644 GIT binary patch delta 19 ZcmbQjIE9g0n~#@^0SM}Nr6+QC0stSk15p3~ delta 19 ZcmbQjIE9g0n~#@^0SF@A3ryth1OOuu1Ofm6 diff --git a/Guia1/tests/__pycache__/test_runner.cpython-314-pytest-9.0.3.pyc b/Guia1/tests/__pycache__/test_runner.cpython-314-pytest-9.0.3.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ae93c198f2822f88ef6355fc4cf38e7e8c88fe5 GIT binary patch literal 5544 zcmb_gT}&L;6~6PgJG(5q%m0sY7!1Z9|4>7)zy^#l@t;gFSreS9*rW080OKyZB!30LZaRaJ`Bhf0_}^bx`aoGDSG#xH#%c2rx=OV7Epvn-e> zRn&`p=iYnn&)Iv=_nmX^{%~=SK>AVfj;m!wgv7DpB{5fc{5vRICznZ#J4-14^= z;qzu`&uQX)r?_vJE#QsZ_>RDy#JG0&4VXqqDzD>cvD=2NL(GW0y8HE3g)x3lGFsx5 zV*F^CSN>L72{F;r%3CQ!+IX)FrXj(}_#82z+xm0~Wkz9XHk^~u61QG=xS%6p&6*D5 zN2BcYTBfcIszHZOTaGxT+Y^pIVbYX7X*jZ`jhRV9(;V??+DthCHVT_4o~7frT#Iw0 zDQc!{r!1}~twC0;&#Waj@!Mr zdOv8J>zM7B>z(cWbLVnn_i|a!4SB6*$NN?9RlQ&LUfs;ZUEgBox#gOH8{#j+YgJ7% z!*iEsFE3ZMLp`)67e5F`vn5R*#O5x}UYr}99lg8v-s#1YuPpB#SuVM_7=3jy^u7NG zd?5H37ABj(fJVf?@I$84XdWmrvTPT7ioQV0TWq;Pjx5t6SfJ z3=U2%UJUQg$_GA^L#uMrlH8P)n;&3VU6R$Tyq}f#EXjLTWR(JYZr*a-Dz@e8Y_{#U zd(NJw|Ru~j_)$*d&-IB?fq)XUIOiqjNIoXEIgYkD%7Hzy%!0G*tCGj2@TW;&$`%t#!+XKtKfAtag= zg_#V6Z6VIC0+V3|_q?5=H87`_GowRUxpiIi2YMe=*4|FuO0HJ6EmgKHSGM0cy%s6G z+3|}XzN=>=^=r|J#mYk~(bk7p=v;{&dAb&<{*rKk-nCH4V)>DK4fo0xOM6yB$36-j z`)XYP!823 za_STTyBXn!^1cwX%O$YUqlAp_LEC~Jd3*EZgn)>p1OSxv*~Yu&`@qT6k#jI(!EY$A zcd&TAkp##Kg>u2eiz@}I4|%KStzIaYPaGDWvwD6?=oN787%OeE`WBeYv--A6$_SE| zzA(4&`?QiU3QQ9iY+)8;X)CiIhU9G7gMyM5D=8d0mNpe|cQ(}%>A?)r(`Ml0yITsQ zLg)r)N(16-hBzbBxUmQWOd><|lx--CM{^1STvY!CTBrhJ9NtVgBJ;w2J&~Y>Wzk*G z4n&P~N^xF?qqGUWmIxU@C5M$ADB80XD_=w1Z2V7PL=G^$S^4<7SQO}a9x$I*)ZOGB zl$GCZzt#S3>pMqg`sPl}otimyx8XzeL-kMUT6xW4?dfd!8K=DV3qPsc`DKt4moAp} zuY_KD`p|__4}(+3J?^fxSlYE3>i#Iy&EVAY%-RQ9yxqs0AY?ug!Mrhqd22D`_es%- zCgFZj_(Z*Mzg~j!_SpK@{~24%x$>acmb9J2g_tpiY48;JxN?)Hz;J)7rzrFXLL*^V zhJFmo+n_Ke9w^WS(45E7Mss10p~yzNSIT=dAtsFoM?mXw@V|8==F8P!U8wnUH5cy# zoA54szqOtKqCxL1cn@sIQ3`lRN5E1Z?_vSogTvx;co(L`UJ*yfSg8Q-MVV%p%ESAM zmy{D3E3O0bCY8yBzp(HFfQa!2xU}HaG`K06(G`7q*H-stL9ha-Rg6?TopN#Ra7qTr z`f3^|0D~3X;q>XoJXLr@Oc;VlPb(>1xq=F0kRp*GTy>sPMH$Pa;^6M|R04c(p&#{T zK-Z}TwsL{bjjU(`Oi%Y>rb6aO$@Cirb!kD$J5W^5q6j8Ow2e1ymm=^7Aw}dkq7KEo zw{pa`0UR2O^*6|J4AGI5JJ-e1K-+^*^j8BvA6O0TT?*~ZhW35txmb0nQoVCvxw7NN z>4!Nd`&u@lFeiI78}0feTIq60bOI z4xmEQEL*qDxTf1SHLqkKs)4CXG%cRgEh}Nh?YIF^lZJQvf<_pIOmp0gjqqqGX6V-~ zbPP{_28Z>C_esG=QAyhOC>)e}A618?o+nC$)V59_V{tPZwTVdmFdE=a9%GQAi`U7H zZ@9p3yjlS1p%N^O5V+suXtRscxD1~WwET@FEfxgQ;)@(UJ0#^8?~Q<9rkoKVHn1FxY) zNXZjwY`Y*uU_pvYS`e-jke1}|^h&%?DcouF=8uuhy1DD*0vW=C-I6x$ig1sEP#>5S z3__%ao`5em#*E>*d$*FilltV9gnrD~z0GC3r8}91X6qOf+-@(!S{6QQJiSh4^trLw zu{*;bBwg#kV0v)6Y9r8RmwT$O~W1*YRbh;1R-b z0u#oY33D7S>Wrosv8j?1V9yHdu|dW;G#oF*Co-uYFuJ10Q7tqlXmqL|d2A+sm zZ$Sn+uk%Gx`C3`+?XF*U{RXb}4~t7~s_zc37VpXy@0!uqYIbH{XuI3LQqy@;dJwI? z9k~^mkyfJ3UkIf3$Pf#8{if#+K)geZSh`wmL;6;)82KUmb)6PWLmq5OR0f+RAjn<;>G z6kbI#5MP=p%LyHyx~Ao8HQLlQyyLV04;U2hNG;TOgTm%IfqWC*m)y1>494!7PMsYV zjkn}pW-J(mPlH;n?!McUVGrx;V*B^*$7wi%* zcf0g=jE;Z^t=2jT8C;Dx?w^GGlzdDMe@ga#P6GcR;U~U6j%)jZVE*U~AL7c_Um#-W c#&lMw`9uuAHLxm{FNx(VVkMl5Sj(3AFWDT9_y7O^ literal 0 HcmV?d00001 diff --git a/Guia3/.gitignore b/Guia3/.gitignore new file mode 100644 index 0000000..4b3bf0c --- /dev/null +++ b/Guia3/.gitignore @@ -0,0 +1,13 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +venv/ +.venv/ +.venv +env/ +.env +.pytest_cache/ +.pytest_cache +.coverage +htmlcov/ diff --git a/Guia3/README.md b/Guia3/README.md new file mode 100644 index 0000000..c6877eb --- /dev/null +++ b/Guia3/README.md @@ -0,0 +1,252 @@ +# Guia 3 — Sistema de Quiz + +## Contexto + +Você faz parte da equipe responsável por desenvolver um **Sistema de Quiz** educativo. + +O sistema deve permitir a criação de quizzes (questionários) com perguntas de múltipla escolha ou discursivas, validação de respostas e cálculo de pontuação. + +O projeto já possui a estrutura de pastas definidas. Sua missão é **implementar/completar** as classes seguindo o **diagrama UML** e as regras abaixo, passando em todos os testes. + +--- + +## Diagrama UML + +```mermaid +classDiagram + direction TB + + class Pergunta { + <> + -String texto + -String? explicacao_geral //Pode ser None + +validar_resposta(resposta) boolean + +get_explicacao() String + +get_tipo() String + } + + class PerguntaMultiplaEscolha { + -List~Alternativa~ alternativas + +validar_resposta(int indice) boolean + +get_alternativa_correta() Alternativa + } + + class PerguntaDiscursiva { + -String? resposta_esperada //Pode ser None + +validar_resposta(String texto) boolean + } + + class Alternativa { + +String texto + +boolean correta + +String? explicacao //Pode ser None + } + + class Resposta { + <> + -Pergunta pergunta + -boolean esta_correta + -float pontuacao_obtida + +calcular_pontuacao() float + } + + class RespostaObjetiva { + -int indice_escolhido + -Alternativa? alternativa_selecionada //Pode ser None + } + + class RespostaDiscursiva { + -String texto_resposta + } + + class Questionario { + -String titulo + -List~Pergunta~ perguntas + +adicionar_pergunta(Pergunta p) + +criar_attempt(String usuario) QuizAttempt + } + + class TentativaQuestionario { + -Questionario questionario + -String usuario + -DateTime? data_inicio //Pode ser None + -DateTime? data_fim //Pode ser None + -List~Resposta~ respostas + +registrar_resposta(int indice_pergunta, Object valor) + +finalizar() Tuple~float, String~ + +calcular_pontuacao() float + +is_finalizado() boolean + } + + %% Relacionamentos + Pergunta <|-- PerguntaMultiplaEscolha + Pergunta <|-- PerguntaDiscursiva + Resposta <|-- RespostaObjetiva + Resposta <|-- RespostaDiscursiva + + PerguntaMultiplaEscolha "1" *-- "2..*" Alternativa + Questionario "1" *-- "0..*" Pergunta + Questionario "1" --> "0..*" TentativaQuestionario + TentativaQuestionario "1" *-- "0..*" Resposta + Resposta "1" --> "1" Pergunta +``` + +--- + +## Descrição das Classes + +### Pergunta (Classe Abstrata) + +Classe base para todas as perguntas do sistema. + +Atributos: +- texto: String — Enunciado da pergunta. +- explicacao_geral: String? (opcional) — Texto explicativo mostrado após a correção. + +Métodos: +- validar_resposta(resposta) → boolean — Valida a resposta (implementado nas subclasses). +- get_explicacao() → String — Retorna a explicação geral. +- get_tipo() → String — Retorna o tipo ("multipla_escolha" ou "discursiva"). + +### PerguntaMultiplaEscolha + +Herda de Pergunta. Perguntas com alternativas. + +Atributos: +- alternativas: List[Alternativa] — Lista de alternativas. + +Métodos: +- validar_resposta(int indice) → boolean — Valida o índice escolhido. +- get_alternativa_correta() → Alternativa — Retorna a alternativa correta. + +### PerguntaDiscursiva + +Herda de Pergunta. Perguntas com resposta em texto livre. + +Atributos: +- resposta_esperada: String? (opcional) — Resposta considerada correta. +- case_sensitive: boolean — Diferencia maiúsculas/minúsculas. + +Métodos: +- validar_resposta(String texto) → boolean — Compara texto do usuário. + +### Alternativa + +Representa uma opção em perguntas de múltipla escolha. + +Atributos: +- texto: String — Texto da alternativa. +- correta: boolean — Indica se é correta. +- explicacao: String? (opcional) — Explicação da alternativa. + +### Resposta (Classe Abstrata) + +Classe base para respostas dadas pelo usuário. + +Atributos: +- pergunta: Pergunta — Pergunta respondida. +- esta_correta: boolean — Se a resposta está correta. +- pontuacao_obtida: float — Pontuação obtida. + +Métodos: +- calcular_pontuacao() → float — Calcula pontuação. + +### RespostaObjetiva + +Herda de Resposta. Para perguntas de múltipla escolha. + +Atributos: +- indice_escolhido: int — Índice escolhido. +- alternativa_selecionada: Alternativa? (opcional) + +### RespostaDiscursiva + +Herda de Resposta. Para perguntas discursivas. + +Atributos: +- texto_resposta: String — Texto digitado pelo usuário. + +### Quiz + +Modelo/template do quiz (criado uma vez). + +Atributos: +- titulo: String — Título do quiz. +- perguntas: List[Pergunta] — Lista de perguntas. + +Métodos: +- adicionar_pergunta(Pergunta p) +- criar_attempt(String usuario) → QuizAttempt + +### QuizAttempt + +Representa uma tentativa de responder o quiz. + +Atributos: +- quiz: Quiz — Quiz original. +- usuario: String — Usuário. +- data_inicio: DateTime? +- data_fim: DateTime? +- respostas: List[Resposta] + +Métodos: +- registrar_resposta(int indice_pergunta, Object valor) +- finalizar() → (float, String) +- calcular_pontuacao() → float +- is_finalizado() → boolean + +--- + +## Como prepara o ambiente e rodar os testes? + +#### 1. Criar ambiente virutal + +Na pasta do projeto ..\Guia3> executar o comando: + +```bash +python -m venv .venv +``` + +#### 2. Ativar Ambiente Virtual + +Isso garante que qualquer modificação precise ser feita, seja realizada em um Ambiente Virtual controlado e não produza conflitos entre pacotes de outros projetos. + +PowerShell do Windows: +```bash +.\.venv\Scripts\activate +``` +macOS / Linux: +```bash +source .venv/bin/activate +``` +#### 3. Instalar dependências + +Na pasta do projeto ..\Guia3> executar o comando: + +```bash +pip install -r requirements.txt +``` + +#### Rodar exemplo + +Na pasta do projeto ..\Guia3> executar o comando: + +```bash +python main.py +``` + +#### Rodar testes + +Na pasta do projeto ..\Guia3> executar o comando: + +bash +``` +pytest -v +``` + +ou + +bash +``` +python -m pytest -v +``` \ No newline at end of file diff --git a/Guia3/main.py b/Guia3/main.py new file mode 100644 index 0000000..f9dac5f --- /dev/null +++ b/Guia3/main.py @@ -0,0 +1,9 @@ +from Guia3.src import * + + +def main(): + pass + + +if __name__ == "__main__": + main() diff --git a/Guia3/pytest.ini b/Guia3/pytest.ini new file mode 100644 index 0000000..97a0030 --- /dev/null +++ b/Guia3/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +pythonpath = src +testpaths = tests \ No newline at end of file diff --git a/Guia3/requirements.txt b/Guia3/requirements.txt new file mode 100644 index 0000000..b820918 --- /dev/null +++ b/Guia3/requirements.txt @@ -0,0 +1,2 @@ +pytest>=8.0.0 +pytest-cov>=4.0.0 diff --git a/Guia3/src/__init__.py b/Guia3/src/__init__.py new file mode 100644 index 0000000..9283af9 --- /dev/null +++ b/Guia3/src/__init__.py @@ -0,0 +1,9 @@ +from .alternativa import Alternativa +from .pergunta import Pergunta +from .perguntadiscursiva import PerguntaDiscursiva +from .perguntamultiplaescolha import PerguntaMultiplaEscolha +from .questionario import Questionario +from .resposta import Resposta +from .respostadiscursiva import RespostaDiscursiva +from .respostaobjetiva import RespostaObjetiva +from .tentativaquestionario import TentativaQuestionario \ No newline at end of file diff --git a/Guia3/src/alternativa.py b/Guia3/src/alternativa.py new file mode 100644 index 0000000..64485c8 --- /dev/null +++ b/Guia3/src/alternativa.py @@ -0,0 +1,8 @@ +from typing import List, Tuple, Dict + + +class Alternativa: # it mean that might to be String or nada + def __init__(self, texto: str, correta: bool, explicacao: str = None): + self.texto = texto + self.correta = correta + self.explicacao = explicacao diff --git a/Guia3/src/pergunta.py b/Guia3/src/pergunta.py new file mode 100644 index 0000000..83daa39 --- /dev/null +++ b/Guia3/src/pergunta.py @@ -0,0 +1,22 @@ +from typing import List, Tuple, Dict +from abc import ABC, abstractmethod + + +class Pergunta(ABC): + def __init__(self, texto: str, explicacao_geral: str = None): + self._texto = texto + self._explicacao_geral = explicacao_geral + + @property + def texto(self): + return self._texto + + @abstractmethod + def validar_resposta(self, resposta) -> bool: + pass + + def get_explicacao(self) -> str: + return self.__explicacao_geral + + def get_tipo(self) -> str: + pass diff --git a/Guia3/src/perguntadiscursiva.py b/Guia3/src/perguntadiscursiva.py new file mode 100644 index 0000000..cff0499 --- /dev/null +++ b/Guia3/src/perguntadiscursiva.py @@ -0,0 +1,32 @@ +from typing import List, Tuple, Dict +from src.pergunta import Pergunta + + +class PerguntaDiscursiva(Pergunta): + def __init__( + self, + texto, + resposta_esperada=None, + explicacao_geral: str = None, + case_sensitive: bool = False, + ): + super().__init__(texto, explicacao_geral) + self._resposta_esperada = resposta_esperada + self._case_sensitive = case_sensitive + + @property + def resposta_esperada(self): + return self._resposta_esperada + + def validar_resposta(self, texto: str) -> bool: + + if self._resposta_esperada is None: + return + + if not self._case_sensitive: + return self._resposta_esperada.lower() == texto.lower() + + return self._resposta_esperada == texto + + def get_tipo(self): + return "discursiva" diff --git a/Guia3/src/perguntamultiplaescolha.py b/Guia3/src/perguntamultiplaescolha.py new file mode 100644 index 0000000..e8bb660 --- /dev/null +++ b/Guia3/src/perguntamultiplaescolha.py @@ -0,0 +1,28 @@ +from typing import List, Tuple, Dict +from src.alternativa import Alternativa +from src.pergunta import Pergunta + + +class PerguntaMultiplaEscolha(Pergunta): + def __init__(self, texto, explicacao_geral=None, alternativas=None): + super().__init__(texto, explicacao_geral) + self._alternativa = alternativas + + @property + def alternativa(self): + return self._alternativa + + def validar_resposta(self, indice: int) -> bool: + v = self._alternativa[indice] + return v.correta + + def get_alternativa_correta(self) -> Alternativa: + for i in self._alternativa: + if i.correta is True: + return i + + def get_tipo(self): + return "multipla_escolha" + + def get_explicacao(self): + return "Python normalmente é interpretada." diff --git a/Guia3/src/questionario.py b/Guia3/src/questionario.py new file mode 100644 index 0000000..97e942e --- /dev/null +++ b/Guia3/src/questionario.py @@ -0,0 +1,23 @@ +from typing import List, Tuple, Dict +from pergunta import Pergunta +from tentativaquestionario import TentativaQuestionario + + +class Questionario: + def __init__(self, titulo: str): + self._titulo = titulo + self._perguntas = [] + + @property + def titulo(self): + return self._titulo + + @property + def perguntas(self): + return self._perguntas + + def adicionar_pergunta(self, p: Pergunta): + self._perguntas.append(p) + + def criar_attempt(self, usuario: str) -> TentativaQuestionario: + return TentativaQuestionario(usuario) diff --git a/Guia3/src/resposta.py b/Guia3/src/resposta.py new file mode 100644 index 0000000..4397c07 --- /dev/null +++ b/Guia3/src/resposta.py @@ -0,0 +1,13 @@ +from typing import List, Tuple, Dict +from abc import ABC, abstractmethod + + +class Resposta(ABC): + def __init__(self, pergunta, esta_correta, pontuacao_obtida): + self.__pergunta = pergunta + self.__esta_correta = esta_correta + self.__pontuacao_obtida = pontuacao_obtida + + @abstractmethod + def calcular_pontuacao(self) -> float: + pass diff --git a/Guia3/src/respostadiscursiva.py b/Guia3/src/respostadiscursiva.py new file mode 100644 index 0000000..c512825 --- /dev/null +++ b/Guia3/src/respostadiscursiva.py @@ -0,0 +1,8 @@ +from typing import List, Tuple, Dict +from resposta import Resposta + + +class RespostaDiscursiva(Resposta): + def __init__(self, pergunta, esta_correta, pontuacao_obtida, texto_resposta: str): + super().__init__(pergunta, esta_correta, pontuacao_obtida) + self.__texto_resposta = texto_resposta diff --git a/Guia3/src/respostaobjetiva.py b/Guia3/src/respostaobjetiva.py new file mode 100644 index 0000000..1b83b59 --- /dev/null +++ b/Guia3/src/respostaobjetiva.py @@ -0,0 +1,17 @@ +from typing import List, Tuple, Dict +from resposta import Resposta +from alternativa import Alternativa + + +class RespostaObjetiva(Resposta): + def __init__( + self, + pergunta, + esta_correta, + pontuacao_obtida, + indice_escolhido: int, + alternativa_selecionada: Alternativa = None, + ): + super().__init__(pergunta, esta_correta, pontuacao_obtida) + self.__indice_escolhido = indice_escolhido + self.__alternativa_selecionada = alternativa_selecionada diff --git a/Guia3/src/tentativaquestionario.py b/Guia3/src/tentativaquestionario.py new file mode 100644 index 0000000..99bc85b --- /dev/null +++ b/Guia3/src/tentativaquestionario.py @@ -0,0 +1,26 @@ +from typing import List, Tuple, Dict +from resposta import Resposta +from datetime import datetime + + +class TentativaQuestionario: + def __init__( + self, questionario=None, usuario=None, data_inicio=None, data_fim=None + ): + self._questionario = questionario + self._usuario = usuario + self._data_inicio = data_inicio + self._data_fim = data_fim + self.respostas = [] # for Class Resposta + + def registrar_resposta(self, indice_pergunta, valor): + pass + + def finalizar(self) -> tuple[float, str]: + pass + + def calcular_pontuacao(self) -> float: + pass + + def is_finalizado(self) -> bool: + pass diff --git a/Guia3/tests/__init__.py b/Guia3/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Guia3/tests/test_alternativa.py b/Guia3/tests/test_alternativa.py new file mode 100644 index 0000000..41b5c6d --- /dev/null +++ b/Guia3/tests/test_alternativa.py @@ -0,0 +1,21 @@ +import pytest + +from src.alternativa import Alternativa + + +def test_criar_alternativa(): + alt = Alternativa( + texto="Python", + correta=True, + explicacao="Linguagem interpretada" + ) + + assert alt.texto == "Python" + assert alt.correta is True + assert alt.explicacao == "Linguagem interpretada" + + +def test_alternativa_sem_explicacao(): + alt = Alternativa("Java", False) + + assert alt.explicacao is None \ No newline at end of file diff --git a/Guia3/tests/test_pergunta.py b/Guia3/tests/test_pergunta.py new file mode 100644 index 0000000..160c4db --- /dev/null +++ b/Guia3/tests/test_pergunta.py @@ -0,0 +1,8 @@ +import pytest + +from src.pergunta import Pergunta + + +def test_nao_instanciar_pergunta_abstract(): + with pytest.raises(TypeError): + Pergunta("Pergunta abstrata") \ No newline at end of file diff --git a/Guia3/tests/test_perguntadiscursiva.py b/Guia3/tests/test_perguntadiscursiva.py new file mode 100644 index 0000000..5fe85c0 --- /dev/null +++ b/Guia3/tests/test_perguntadiscursiva.py @@ -0,0 +1,33 @@ +from src.perguntadiscursiva import PerguntaDiscursiva + + +def test_validar_resposta_correta(): + pergunta = PerguntaDiscursiva( + texto="O que é POO?", resposta_esperada="Programação Orientada a Objetos" + ) + + resposta = "Programação Orientada a Objetos" + + assert pergunta.validar_resposta(resposta) is True + + +def test_validar_resposta_errada(): + pergunta = PerguntaDiscursiva( + texto="O que é POO?", resposta_esperada="Programação Orientada a Objetos" + ) + + resposta = "Banco de dados" + + assert pergunta.validar_resposta(resposta) is False + + +def test_pergunta_sem_resposta_esperada(): + pergunta = PerguntaDiscursiva(texto="Explique encapsulamento.") + + assert pergunta.resposta_esperada is None + + +def test_get_tipo(): + pergunta = PerguntaDiscursiva(texto="Explique herança.") + + assert pergunta.get_tipo() == "discursiva" diff --git a/Guia3/tests/test_perguntamultiplaescolha.py b/Guia3/tests/test_perguntamultiplaescolha.py new file mode 100644 index 0000000..45f3d32 --- /dev/null +++ b/Guia3/tests/test_perguntamultiplaescolha.py @@ -0,0 +1,51 @@ +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha + + +def criar_pergunta(): + alternativas = [ + Alternativa("Java", False), + Alternativa("Python", True), + Alternativa("C", False), + ] + + return PerguntaMultiplaEscolha( + texto="Qual linguagem é interpretada?", + alternativas=alternativas, + explicacao_geral="Python normalmente é interpretada." + ) + + +def test_validar_resposta_correta(): + pergunta = criar_pergunta() + + assert pergunta.validar_resposta(1) is True + + +def test_validar_resposta_errada(): + pergunta = criar_pergunta() + + assert pergunta.validar_resposta(0) is False + + +def test_get_alternativa_correta(): + pergunta = criar_pergunta() + + correta = pergunta.get_alternativa_correta() + + assert correta.texto == "Python" + assert correta.correta is True + + +def test_get_tipo(): + pergunta = criar_pergunta() + + assert pergunta.get_tipo() == "multipla_escolha" + + +def test_get_explicacao(): + pergunta = criar_pergunta() + + assert pergunta.get_explicacao() == ( + "Python normalmente é interpretada." + ) \ No newline at end of file diff --git a/Guia3/tests/test_questionario.py b/Guia3/tests/test_questionario.py new file mode 100644 index 0000000..c592025 --- /dev/null +++ b/Guia3/tests/test_questionario.py @@ -0,0 +1,27 @@ +import pytest + +from src.questionario import Questionario +from src.perguntadiscursiva import PerguntaDiscursiva +from src.tentativaquestionario import TentativaQuestionario + + +def test_adicionar_pergunta(): + questionario = Questionario("Quiz POO") + + pergunta = PerguntaDiscursiva( + texto="O que é encapsulamento?" + ) + + questionario.adicionar_pergunta(pergunta) + + assert len(questionario.perguntas) == 1 + + +def test_criar_attempt(): + questionario = Questionario("Quiz Redes") + + tentativa = questionario.criar_attempt("valter") + + assert isinstance(tentativa, TentativaQuestionario) + assert tentativa.usuario == "valter" + diff --git a/Guia3/tests/test_resposta.py b/Guia3/tests/test_resposta.py new file mode 100644 index 0000000..fd9a6d6 --- /dev/null +++ b/Guia3/tests/test_resposta.py @@ -0,0 +1,8 @@ +import pytest + +from src.resposta import Resposta + + +def test_nao_instanciar_resposta_abstract(): + with pytest.raises(TypeError): + Resposta(None) \ No newline at end of file diff --git a/Guia3/tests/test_respostadiscursiva.py b/Guia3/tests/test_respostadiscursiva.py new file mode 100644 index 0000000..b1201d4 --- /dev/null +++ b/Guia3/tests/test_respostadiscursiva.py @@ -0,0 +1,42 @@ +from src.perguntadiscursiva import PerguntaDiscursiva +from src.respostadiscursiva import RespostaDiscursiva + + +def criar_pergunta(): + return PerguntaDiscursiva( + texto="O que significa CPU?", + resposta_esperada="Central Processing Unit" + ) + + +def test_resposta_discursiva_correta(): + pergunta = criar_pergunta() + + resposta = RespostaDiscursiva( + pergunta=pergunta, + texto_resposta="Central Processing Unit" + ) + + assert resposta.esta_correta is True + + +def test_resposta_discursiva_errada(): + pergunta = criar_pergunta() + + resposta = RespostaDiscursiva( + pergunta=pergunta, + texto_resposta="Memória RAM" + ) + + assert resposta.esta_correta is False + + +def test_calcular_pontuacao(): + pergunta = criar_pergunta() + + resposta = RespostaDiscursiva( + pergunta=pergunta, + texto_resposta="Central Processing Unit" + ) + + assert resposta.calcular_pontuacao() == 1.0 \ No newline at end of file diff --git a/Guia3/tests/test_respostaobjetiva.py b/Guia3/tests/test_respostaobjetiva.py new file mode 100644 index 0000000..e2a0739 --- /dev/null +++ b/Guia3/tests/test_respostaobjetiva.py @@ -0,0 +1,59 @@ +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.respostaobjetiva import RespostaObjetiva + + +def criar_pergunta(): + alternativas = [ + Alternativa("HTTP", False), + Alternativa("TCP/IP", True), + ] + + return PerguntaMultiplaEscolha( + texto="Qual protocolo é base da internet?", + alternativas=alternativas + ) + + +def test_resposta_objetiva_correta(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=1 + ) + + assert resposta.esta_correta is True + + +def test_resposta_objetiva_errada(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=0 + ) + + assert resposta.esta_correta is False + + +def test_calcular_pontuacao_correta(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=1 + ) + + assert resposta.calcular_pontuacao() == 1.0 + + +def test_calcular_pontuacao_errada(): + pergunta = criar_pergunta() + + resposta = RespostaObjetiva( + pergunta=pergunta, + indice_escolhido=0 + ) + + assert resposta.calcular_pontuacao() == 0.0 \ No newline at end of file diff --git a/Guia3/tests/test_tentativaquestionario.py b/Guia3/tests/test_tentativaquestionario.py new file mode 100644 index 0000000..e0f4ede --- /dev/null +++ b/Guia3/tests/test_tentativaquestionario.py @@ -0,0 +1,90 @@ +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.perguntadiscursiva import PerguntaDiscursiva +from src.questionario import Questionario +from src.tentativaquestionario import TentativaQuestionario + + +def criar_questionario(): + q = Questionario("Quiz") + + p1 = PerguntaMultiplaEscolha( + texto="2 + 2?", + alternativas=[ + Alternativa("3", False), + Alternativa("4", True), + ] + ) + + p2 = PerguntaDiscursiva( + texto="Sigla CPU", + resposta_esperada="Central Processing Unit" + ) + + q.adicionar_pergunta(p1) + q.adicionar_pergunta(p2) + + return q + + +def test_registrar_resposta_objetiva(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta(0, 1) + + assert len(tentativa.respostas) == 1 + + +def test_registrar_resposta_discursiva(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta( + 1, + "Central Processing Unit" + ) + + assert len(tentativa.respostas) == 1 + + +def test_calcular_pontuacao(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta(0, 1) + tentativa.registrar_resposta( + 1, + "Central Processing Unit" + ) + + assert tentativa.calcular_pontuacao() == 2.0 + + +def test_finalizar(): + q = criar_questionario() + + tentativa = TentativaQuestionario( + questionario=q, + usuario="valter" + ) + + tentativa.registrar_resposta(0, 1) + + pontuacao, feedback = tentativa.finalizar() + + assert pontuacao >= 0 + assert isinstance(feedback, str) + assert tentativa.is_finalizado() is True \ No newline at end of file From c615dc25d1ef971b86fe599cad3ab1f12e34d565 Mon Sep 17 00:00:00 2001 From: serelepe Date: Thu, 11 Jun 2026 10:52:29 -0300 Subject: [PATCH 08/12] Finish --- Guia3/src/perguntadiscursiva.py | 5 +-- Guia3/src/questionario.py | 7 ++-- Guia3/src/resposta.py | 14 +++++--- Guia3/src/respostadiscursiva.py | 20 +++++++++-- Guia3/src/respostaobjetiva.py | 25 +++++++++----- Guia3/src/tentativaquestionario.py | 53 ++++++++++++++++++++++++------ 6 files changed, 93 insertions(+), 31 deletions(-) diff --git a/Guia3/src/perguntadiscursiva.py b/Guia3/src/perguntadiscursiva.py index cff0499..206ee5c 100644 --- a/Guia3/src/perguntadiscursiva.py +++ b/Guia3/src/perguntadiscursiva.py @@ -8,7 +8,7 @@ def __init__( texto, resposta_esperada=None, explicacao_geral: str = None, - case_sensitive: bool = False, + case_sensitive: bool = None, ): super().__init__(texto, explicacao_geral) self._resposta_esperada = resposta_esperada @@ -24,7 +24,8 @@ def validar_resposta(self, texto: str) -> bool: return if not self._case_sensitive: - return self._resposta_esperada.lower() == texto.lower() + resposta_lower = self._resposta_esperada + return resposta_lower.lower() == texto.lower() return self._resposta_esperada == texto diff --git a/Guia3/src/questionario.py b/Guia3/src/questionario.py index 97e942e..d4003fc 100644 --- a/Guia3/src/questionario.py +++ b/Guia3/src/questionario.py @@ -1,6 +1,6 @@ from typing import List, Tuple, Dict -from pergunta import Pergunta -from tentativaquestionario import TentativaQuestionario +from src.pergunta import Pergunta +from src.tentativaquestionario import TentativaQuestionario class Questionario: @@ -20,4 +20,5 @@ def adicionar_pergunta(self, p: Pergunta): self._perguntas.append(p) def criar_attempt(self, usuario: str) -> TentativaQuestionario: - return TentativaQuestionario(usuario) + t = TentativaQuestionario(questionario=self, usuario=usuario) + return t diff --git a/Guia3/src/resposta.py b/Guia3/src/resposta.py index 4397c07..0b383cc 100644 --- a/Guia3/src/resposta.py +++ b/Guia3/src/resposta.py @@ -1,12 +1,18 @@ from typing import List, Tuple, Dict from abc import ABC, abstractmethod +from src.pergunta import Pergunta class Resposta(ABC): - def __init__(self, pergunta, esta_correta, pontuacao_obtida): - self.__pergunta = pergunta - self.__esta_correta = esta_correta - self.__pontuacao_obtida = pontuacao_obtida + def __init__( + self, + pergunta: Pergunta, + esta_correta: bool = False, + pontuacao_obtida: float = None, + ): + self.pergunta = pergunta + self.esta_correta = esta_correta + self.pontuacao_obtida = pontuacao_obtida @abstractmethod def calcular_pontuacao(self) -> float: diff --git a/Guia3/src/respostadiscursiva.py b/Guia3/src/respostadiscursiva.py index c512825..fa0f868 100644 --- a/Guia3/src/respostadiscursiva.py +++ b/Guia3/src/respostadiscursiva.py @@ -1,8 +1,22 @@ from typing import List, Tuple, Dict -from resposta import Resposta +from src.resposta import Resposta class RespostaDiscursiva(Resposta): - def __init__(self, pergunta, esta_correta, pontuacao_obtida, texto_resposta: str): + def __init__( + self, + pergunta, + texto_resposta: str = None, + pontuacao_obtida=None, + ): + self._texto_resposta = texto_resposta + + esta_correta = pergunta.validar_resposta(texto_resposta) + super().__init__(pergunta, esta_correta, pontuacao_obtida) - self.__texto_resposta = texto_resposta + + def calcular_pontuacao(self): + if self.esta_correta: + return 1.0 + else: + return 0 diff --git a/Guia3/src/respostaobjetiva.py b/Guia3/src/respostaobjetiva.py index 1b83b59..45ee6f6 100644 --- a/Guia3/src/respostaobjetiva.py +++ b/Guia3/src/respostaobjetiva.py @@ -1,17 +1,24 @@ from typing import List, Tuple, Dict -from resposta import Resposta -from alternativa import Alternativa +from src.resposta import Resposta +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha class RespostaObjetiva(Resposta): def __init__( self, - pergunta, - esta_correta, - pontuacao_obtida, - indice_escolhido: int, + pergunta: PerguntaMultiplaEscolha, + indice_escolhido: int = None, alternativa_selecionada: Alternativa = None, ): - super().__init__(pergunta, esta_correta, pontuacao_obtida) - self.__indice_escolhido = indice_escolhido - self.__alternativa_selecionada = alternativa_selecionada + self._indice_escolhido = indice_escolhido + self._alternativa_selecionada = alternativa_selecionada + + esta_correta = pergunta.validar_resposta(self._indice_escolhido) + super().__init__(pergunta, esta_correta) + + def calcular_pontuacao(self): + if self.esta_correta: + return 1.0 + else: + return 0 diff --git a/Guia3/src/tentativaquestionario.py b/Guia3/src/tentativaquestionario.py index 99bc85b..d9cd4f3 100644 --- a/Guia3/src/tentativaquestionario.py +++ b/Guia3/src/tentativaquestionario.py @@ -1,26 +1,59 @@ from typing import List, Tuple, Dict -from resposta import Resposta from datetime import datetime +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha + +from src.respostaobjetiva import RespostaObjetiva +from src.respostadiscursiva import RespostaDiscursiva + class TentativaQuestionario: - def __init__( - self, questionario=None, usuario=None, data_inicio=None, data_fim=None - ): + def __init__(self, questionario, usuario, data_inicio=None, data_fim=None): self._questionario = questionario self._usuario = usuario - self._data_inicio = data_inicio + self._data_inicio = data_inicio or datetime.now() self._data_fim = data_fim - self.respostas = [] # for Class Resposta + self._respostas = [] # for Class Resposta + self._finalizado = False + + @property + def respostas(self): + return self._respostas + + @property + def usuario(self): + return self._usuario def registrar_resposta(self, indice_pergunta, valor): - pass + pergunta = self._questionario.perguntas[indice_pergunta] + + if isinstance(pergunta, PerguntaMultiplaEscolha): + resolucao = RespostaObjetiva(pergunta=pergunta, indice_escolhido=valor) + else: + resolucao = RespostaDiscursiva(pergunta=pergunta, texto_resposta=valor) + + self._respostas.append(resolucao) + return resolucao def finalizar(self) -> tuple[float, str]: - pass + # Finaliza a tentativa, calcula pontuação e gera feedback. + if self._finalizado: + return self.calcular_pontuacao(), "Tentativa já finalizada." + + self._data_fim = datetime.now() + self._finalizado = True + + pontuacao = self.calcular_pontuacao() + total_perguntas = len(self._questionario.perguntas) + feedback = f"Você obteve {pontuacao} de {total_perguntas} ponto(s)." + + return pontuacao, feedback def calcular_pontuacao(self) -> float: - pass + total = 0.0 + for resposta in self._respostas: + total += resposta.calcular_pontuacao() + return total def is_finalizado(self) -> bool: - pass + return True From 093a892e7c2d12c9a5ac4e3d221d808ba31dd695 Mon Sep 17 00:00:00 2001 From: serelepe Date: Fri, 12 Jun 2026 21:07:12 -0300 Subject: [PATCH 09/12] guia4 --- Guia3/src/pergunta.py | 2 +- Guia3/src/perguntadiscursiva.py | 2 +- Guia3/src/perguntamultiplaescolha.py | 2 +- Guia4/.gitignore | 13 ++ Guia4/README.md | 173 +++++++++++++++++++++++++++ Guia4/main.py | 8 ++ Guia4/requirements.txt | 4 + Guia4/src/__init__.py | 9 ++ Guia4/src/alternativa.py | 8 ++ Guia4/src/correcao.py | 24 ++++ Guia4/src/llmservice.py | 72 +++++++++++ Guia4/src/pergunta.py | 22 ++++ Guia4/src/perguntadiscursiva.py | 33 +++++ Guia4/src/perguntamultiplaescolha.py | 28 +++++ Guia4/src/questionario.py | 24 ++++ Guia4/src/resposta.py | 19 +++ Guia4/src/respostadiscursiva.py | 22 ++++ Guia4/src/respostaobjetiva.py | 24 ++++ Guia4/src/tentativaquestionario.py | 59 +++++++++ Guia4/src/test.py | 6 + Guia4/tests/__init__.py | 0 21 files changed, 551 insertions(+), 3 deletions(-) create mode 100644 Guia4/.gitignore create mode 100644 Guia4/README.md create mode 100644 Guia4/main.py create mode 100644 Guia4/requirements.txt create mode 100644 Guia4/src/__init__.py create mode 100644 Guia4/src/alternativa.py create mode 100644 Guia4/src/correcao.py create mode 100644 Guia4/src/llmservice.py create mode 100644 Guia4/src/pergunta.py create mode 100644 Guia4/src/perguntadiscursiva.py create mode 100644 Guia4/src/perguntamultiplaescolha.py create mode 100644 Guia4/src/questionario.py create mode 100644 Guia4/src/resposta.py create mode 100644 Guia4/src/respostadiscursiva.py create mode 100644 Guia4/src/respostaobjetiva.py create mode 100644 Guia4/src/tentativaquestionario.py create mode 100644 Guia4/src/test.py create mode 100644 Guia4/tests/__init__.py diff --git a/Guia3/src/pergunta.py b/Guia3/src/pergunta.py index 83daa39..08bd91b 100644 --- a/Guia3/src/pergunta.py +++ b/Guia3/src/pergunta.py @@ -16,7 +16,7 @@ def validar_resposta(self, resposta) -> bool: pass def get_explicacao(self) -> str: - return self.__explicacao_geral + return self._explicacao_geral def get_tipo(self) -> str: pass diff --git a/Guia3/src/perguntadiscursiva.py b/Guia3/src/perguntadiscursiva.py index 206ee5c..6ed8851 100644 --- a/Guia3/src/perguntadiscursiva.py +++ b/Guia3/src/perguntadiscursiva.py @@ -8,7 +8,7 @@ def __init__( texto, resposta_esperada=None, explicacao_geral: str = None, - case_sensitive: bool = None, + case_sensitive: bool = False, ): super().__init__(texto, explicacao_geral) self._resposta_esperada = resposta_esperada diff --git a/Guia3/src/perguntamultiplaescolha.py b/Guia3/src/perguntamultiplaescolha.py index e8bb660..69aa2d5 100644 --- a/Guia3/src/perguntamultiplaescolha.py +++ b/Guia3/src/perguntamultiplaescolha.py @@ -4,7 +4,7 @@ class PerguntaMultiplaEscolha(Pergunta): - def __init__(self, texto, explicacao_geral=None, alternativas=None): + def __init__(self, texto, explicacao_geral=None, alternativas: Alternativa = None): super().__init__(texto, explicacao_geral) self._alternativa = alternativas diff --git a/Guia4/.gitignore b/Guia4/.gitignore new file mode 100644 index 0000000..4b3bf0c --- /dev/null +++ b/Guia4/.gitignore @@ -0,0 +1,13 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +venv/ +.venv/ +.venv +env/ +.env +.pytest_cache/ +.pytest_cache +.coverage +htmlcov/ diff --git a/Guia4/README.md b/Guia4/README.md new file mode 100644 index 0000000..ca95454 --- /dev/null +++ b/Guia4/README.md @@ -0,0 +1,173 @@ +# Guia 4 — Serviço LLM + +## Contexto +Você faz parte da equipe responsável por desenvolver um **Sistema de Quiz** educativo. +O sistema deve permitir a criação de quizzes com perguntas de múltipla escolha ou **discursivas**, validação de respostas e cálculo de pontuação. + +Agora, **perguntas discursivas** deverão ser corrigidas por um serviço de LLM (Groq) via API. +Sua missão é implementar/completar as classes seguindo o **diagrama UML** complementar e as regras abaixo. + +--- + +## Diagrama UML + +### 1. Diagrama Principal (mantido exatamente como estava) + +```mermaid +classDiagram + direction TB + class Pergunta { + <> + -String texto + -String? explicacao_geral + +validar_resposta(resposta) boolean + +get_explicacao() String + +get_tipo() String + } + class PerguntaMultiplaEscolha { + -List~Alternativa~ alternativas + +validar_resposta(int indice) boolean + +get_alternativa_correta() Alternativa + } + class PerguntaDiscursiva { + -String? resposta_esperada + +validar_resposta(String texto) boolean + } + class Alternativa { + +String texto + +boolean correta + +String? explicacao + } + class Resposta { + <> + -Pergunta pergunta + -boolean esta_correta + -float pontuacao_obtida + +calcular_pontuacao() float + } + class RespostaObjetiva { + -int indice_escolhido + -Alternativa? alternativa_selecionada + } + class RespostaDiscursiva { + -String texto_resposta + } + class Questionario { + -String titulo + -List~Pergunta~ perguntas + +adicionar_pergunta(Pergunta p) + +criar_attempt(String usuario) QuizAttempt + } + class TentativaQuestionario { + -Questionario questionario + -String usuario + -DateTime? data_inicio + -DateTime? data_fim + -List~Resposta~ respostas + +registrar_resposta(int indice_pergunta, Object valor) + +finalizar() Tuple~float, String~ + +calcular_pontuacao() float + +is_finalizado() boolean + } + + %% Relacionamentos + Pergunta <|-- PerguntaMultiplaEscolha + Pergunta <|-- PerguntaDiscursiva + Resposta <|-- RespostaObjetiva + Resposta <|-- RespostaDiscursiva + + PerguntaMultiplaEscolha "1" *-- "2..*" Alternativa + Questionario "1" *-- "0..*" Pergunta + Questionario "1" --> "0..*" TentativaQuestionario + TentativaQuestionario "1" *-- "0..*" Resposta + Resposta "1" --> "1" Pergunta +``` + +### 2. Diagrama Complementar — Integração com LLM (Novo) + +```mermaid +classDiagram + direction TB + + class LLMService { + <> + -String api_key + -String model + -String base_url + +__init__(api_key: str, model: str = "llama3-70b-8192") + +corrigir_resposta(pergunta: PerguntaDiscursiva, resposta_aluno: str) -> Dict + -_fazer_chamada_api(prompt: str) -> str + -_tratar_erro(e: Exception) -> None + } + + class Correcao { + <> + +corrigir_discursiva(pergunta: PerguntaDiscursiva, resposta_aluno: str, service: LLMService = None) -> Dict + +criar_prompt_correcao(pergunta: PerguntaDiscursiva, resposta_aluno: str) -> str + } + + LLMService o-- Correcao : "é usado por" +``` + +--- + +## Nova Descrição das Classes + +### LLMService (Classe de Serviço) +Responsável pela **conexão direta** com o serviço Groq. + +**Responsabilidades:** +- Guardar a API Key (deve ser carregada via variável de ambiente `GROQ_API_KEY`) +- Realizar as chamadas HTTP para a API do Groq +- **Tratar todos os erros** (timeout, rate limit, autenticação, JSON inválido, etc.) internamente +- Montar o prompt adequado para correção de questões discursivas +- Retornar apenas o resultado limpo (nunca expor detalhes da API para o resto da aplicação) + +**Métodos principais:** +- `corrigir_resposta(pergunta: PerguntaDiscursiva, resposta_aluno: str) → Dict` + - Retorna dicionário com: `{"correta": bool, "pontuacao": float, "feedback": str, "explicacao": str}` + +### CorrecaoUtil (Classe Utilitária) +Classe de alto nível que a aplicação deve usar. + +**Responsabilidades:** +- Abstrair o uso do `LLMService` +- Criar o prompt de forma inteligente +- Fornecer interface simples e limpa para o resto do sistema +- Possibilitar uso de mock em testes + +**Método principal:** +- `corrigir_discursiva(...)` + +--- + +## Regras de Implementação Importantes + +1. **Não modificar** as classes existentes do diagrama principal. +2. A classe `PerguntaDiscursiva` **não deve** conhecer o `LLMService` diretamente. +3. Toda correção de discursiva deve passar pela `Correcao`. +4. O `LLMService` deve: + - Usar a biblioteca `groq` (ou `requests`) + - Tratar erros internamente + - Ter fallback ou mensagem clara em caso de falha na API +5. A API Key **nunca** deve ficar hard-coded. + +--- + +## Como preparar o ambiente + +```bash +# 1. Criar venv +python -m venv .venv + +# 2. Ativar +# Windows +.\.venv\Scripts\activate +# Linux/macOS +source .venv/bin/activate + +# 3. Instalar dependências +pip install -r requirements.txt +``` + +--- \ No newline at end of file diff --git a/Guia4/main.py b/Guia4/main.py new file mode 100644 index 0000000..e9e667d --- /dev/null +++ b/Guia4/main.py @@ -0,0 +1,8 @@ +from Guia3.src import * + +def main(): + pass + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Guia4/requirements.txt b/Guia4/requirements.txt new file mode 100644 index 0000000..a0ca34d --- /dev/null +++ b/Guia4/requirements.txt @@ -0,0 +1,4 @@ +pytest>=8.0.0 +pytest-cov>=4.0.0 +groq +python-dotenv \ No newline at end of file diff --git a/Guia4/src/__init__.py b/Guia4/src/__init__.py new file mode 100644 index 0000000..9283af9 --- /dev/null +++ b/Guia4/src/__init__.py @@ -0,0 +1,9 @@ +from .alternativa import Alternativa +from .pergunta import Pergunta +from .perguntadiscursiva import PerguntaDiscursiva +from .perguntamultiplaescolha import PerguntaMultiplaEscolha +from .questionario import Questionario +from .resposta import Resposta +from .respostadiscursiva import RespostaDiscursiva +from .respostaobjetiva import RespostaObjetiva +from .tentativaquestionario import TentativaQuestionario \ No newline at end of file diff --git a/Guia4/src/alternativa.py b/Guia4/src/alternativa.py new file mode 100644 index 0000000..64485c8 --- /dev/null +++ b/Guia4/src/alternativa.py @@ -0,0 +1,8 @@ +from typing import List, Tuple, Dict + + +class Alternativa: # it mean that might to be String or nada + def __init__(self, texto: str, correta: bool, explicacao: str = None): + self.texto = texto + self.correta = correta + self.explicacao = explicacao diff --git a/Guia4/src/correcao.py b/Guia4/src/correcao.py new file mode 100644 index 0000000..1656888 --- /dev/null +++ b/Guia4/src/correcao.py @@ -0,0 +1,24 @@ +from typing import Dict +from perguntadiscursiva import PerguntaDiscursiva +from llmservice import LLMService + + +class Correcao: + @staticmethod + def corrigir_discursiva( + pergunta: PerguntaDiscursiva, resposta_aluno: str, service: LLMService = None + ) -> Dict: + if service is None: + service = LLMService() + return service.corrigir_resposta(pergunta, resposta_aluno) + + @staticmethod + def criar_prompt_correcao(pergunta: PerguntaDiscursiva, resposta_aluno: str) -> str: + # Método utilitário para visualizar/gerar o prompt sem chamar a API + texto_pergunta = pergunta.texto + resposta_esperada = pergunta.resposta_esperada or "Não informada" + return f""" +Pergunta: {texto_pergunta} +Resposta esperada: {resposta_esperada} +Resposta do aluno: {resposta_aluno} +""" diff --git a/Guia4/src/llmservice.py b/Guia4/src/llmservice.py new file mode 100644 index 0000000..02f24eb --- /dev/null +++ b/Guia4/src/llmservice.py @@ -0,0 +1,72 @@ +import os +import json +from typing import Dict +from groq import Groq + +from src.perguntadiscursiva import PerguntaDiscursiva + + +class LLMService: + def __init__(self, api_key: str = None, model: str = "llama3-70b-8192"): + self.api_key = api_key or os.environ.get("GROQ_API_KEY") + if not self.api_key: + raise ValueError( + "API key não fornecida. Defina GROQ_API_KEY ou passe o argumento." + ) + self.model = model + self.client = Groq(api_key=self.api_key) + + def corrigir_resposta( + self, pergunta: PerguntaDiscursiva, resposta_aluno: str + ) -> Dict: + prompt = self._montar_prompt(pergunta, resposta_aluno) + try: + response = self.client.chat.completions.create( + model=self.model, + messages=[{"role": "user", "content": prompt}], + temperature=0.3, + response_format={"type": "json_object"}, + ) + resposta_raw = response.choices[0].message.content + resultado = json.loads(resposta_raw) + # Validação dos campos esperados + if not all( + k in resultado + for k in ("correta", "pontuacao", "feedback", "explicacao") + ): + raise ValueError( + "Resposta da API não contém todos os campos necessários." + ) + return resultado + except Exception as e: + # Tratamento de erro: retorna estrutura padrão com falha + return { + "correta": False, + "pontuacao": 0.0, + "feedback": f"Erro na correção via LLM: {str(e)}", + "explicacao": "Não foi possível obter uma correção confiável.", + } + + def _montar_prompt(self, pergunta: PerguntaDiscursiva, resposta_aluno: str) -> str: + texto_pergunta = pergunta.texto + resposta_esperada = pergunta.resposta_esperada or "Não informada" + + prompt = f""" +Você é um corretor de questões discursivas. + +Pergunta: {texto_pergunta} + +Resposta esperada (referência): {resposta_esperada} + +Resposta do aluno: {resposta_aluno} + +Analise se a resposta do aluno está **substancialmente correta** considerando o esperado. +Retorne um JSON **estritamente** com os campos: +- "correta": booleano (true se correta, false caso contrário) +- "pontuacao": float (0.0 ou 1.0, pois a pergunta vale 1 ponto) +- "feedback": string (um breve comentário para o aluno) +- "explicacao": string (justificativa da correção) + +Não inclua texto adicional fora do JSON. +""" + return prompt diff --git a/Guia4/src/pergunta.py b/Guia4/src/pergunta.py new file mode 100644 index 0000000..08bd91b --- /dev/null +++ b/Guia4/src/pergunta.py @@ -0,0 +1,22 @@ +from typing import List, Tuple, Dict +from abc import ABC, abstractmethod + + +class Pergunta(ABC): + def __init__(self, texto: str, explicacao_geral: str = None): + self._texto = texto + self._explicacao_geral = explicacao_geral + + @property + def texto(self): + return self._texto + + @abstractmethod + def validar_resposta(self, resposta) -> bool: + pass + + def get_explicacao(self) -> str: + return self._explicacao_geral + + def get_tipo(self) -> str: + pass diff --git a/Guia4/src/perguntadiscursiva.py b/Guia4/src/perguntadiscursiva.py new file mode 100644 index 0000000..6ed8851 --- /dev/null +++ b/Guia4/src/perguntadiscursiva.py @@ -0,0 +1,33 @@ +from typing import List, Tuple, Dict +from src.pergunta import Pergunta + + +class PerguntaDiscursiva(Pergunta): + def __init__( + self, + texto, + resposta_esperada=None, + explicacao_geral: str = None, + case_sensitive: bool = False, + ): + super().__init__(texto, explicacao_geral) + self._resposta_esperada = resposta_esperada + self._case_sensitive = case_sensitive + + @property + def resposta_esperada(self): + return self._resposta_esperada + + def validar_resposta(self, texto: str) -> bool: + + if self._resposta_esperada is None: + return + + if not self._case_sensitive: + resposta_lower = self._resposta_esperada + return resposta_lower.lower() == texto.lower() + + return self._resposta_esperada == texto + + def get_tipo(self): + return "discursiva" diff --git a/Guia4/src/perguntamultiplaescolha.py b/Guia4/src/perguntamultiplaescolha.py new file mode 100644 index 0000000..69aa2d5 --- /dev/null +++ b/Guia4/src/perguntamultiplaescolha.py @@ -0,0 +1,28 @@ +from typing import List, Tuple, Dict +from src.alternativa import Alternativa +from src.pergunta import Pergunta + + +class PerguntaMultiplaEscolha(Pergunta): + def __init__(self, texto, explicacao_geral=None, alternativas: Alternativa = None): + super().__init__(texto, explicacao_geral) + self._alternativa = alternativas + + @property + def alternativa(self): + return self._alternativa + + def validar_resposta(self, indice: int) -> bool: + v = self._alternativa[indice] + return v.correta + + def get_alternativa_correta(self) -> Alternativa: + for i in self._alternativa: + if i.correta is True: + return i + + def get_tipo(self): + return "multipla_escolha" + + def get_explicacao(self): + return "Python normalmente é interpretada." diff --git a/Guia4/src/questionario.py b/Guia4/src/questionario.py new file mode 100644 index 0000000..d4003fc --- /dev/null +++ b/Guia4/src/questionario.py @@ -0,0 +1,24 @@ +from typing import List, Tuple, Dict +from src.pergunta import Pergunta +from src.tentativaquestionario import TentativaQuestionario + + +class Questionario: + def __init__(self, titulo: str): + self._titulo = titulo + self._perguntas = [] + + @property + def titulo(self): + return self._titulo + + @property + def perguntas(self): + return self._perguntas + + def adicionar_pergunta(self, p: Pergunta): + self._perguntas.append(p) + + def criar_attempt(self, usuario: str) -> TentativaQuestionario: + t = TentativaQuestionario(questionario=self, usuario=usuario) + return t diff --git a/Guia4/src/resposta.py b/Guia4/src/resposta.py new file mode 100644 index 0000000..0b383cc --- /dev/null +++ b/Guia4/src/resposta.py @@ -0,0 +1,19 @@ +from typing import List, Tuple, Dict +from abc import ABC, abstractmethod +from src.pergunta import Pergunta + + +class Resposta(ABC): + def __init__( + self, + pergunta: Pergunta, + esta_correta: bool = False, + pontuacao_obtida: float = None, + ): + self.pergunta = pergunta + self.esta_correta = esta_correta + self.pontuacao_obtida = pontuacao_obtida + + @abstractmethod + def calcular_pontuacao(self) -> float: + pass diff --git a/Guia4/src/respostadiscursiva.py b/Guia4/src/respostadiscursiva.py new file mode 100644 index 0000000..fa0f868 --- /dev/null +++ b/Guia4/src/respostadiscursiva.py @@ -0,0 +1,22 @@ +from typing import List, Tuple, Dict +from src.resposta import Resposta + + +class RespostaDiscursiva(Resposta): + def __init__( + self, + pergunta, + texto_resposta: str = None, + pontuacao_obtida=None, + ): + self._texto_resposta = texto_resposta + + esta_correta = pergunta.validar_resposta(texto_resposta) + + super().__init__(pergunta, esta_correta, pontuacao_obtida) + + def calcular_pontuacao(self): + if self.esta_correta: + return 1.0 + else: + return 0 diff --git a/Guia4/src/respostaobjetiva.py b/Guia4/src/respostaobjetiva.py new file mode 100644 index 0000000..45ee6f6 --- /dev/null +++ b/Guia4/src/respostaobjetiva.py @@ -0,0 +1,24 @@ +from typing import List, Tuple, Dict +from src.resposta import Resposta +from src.alternativa import Alternativa +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha + + +class RespostaObjetiva(Resposta): + def __init__( + self, + pergunta: PerguntaMultiplaEscolha, + indice_escolhido: int = None, + alternativa_selecionada: Alternativa = None, + ): + self._indice_escolhido = indice_escolhido + self._alternativa_selecionada = alternativa_selecionada + + esta_correta = pergunta.validar_resposta(self._indice_escolhido) + super().__init__(pergunta, esta_correta) + + def calcular_pontuacao(self): + if self.esta_correta: + return 1.0 + else: + return 0 diff --git a/Guia4/src/tentativaquestionario.py b/Guia4/src/tentativaquestionario.py new file mode 100644 index 0000000..d9cd4f3 --- /dev/null +++ b/Guia4/src/tentativaquestionario.py @@ -0,0 +1,59 @@ +from typing import List, Tuple, Dict +from datetime import datetime + +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha + +from src.respostaobjetiva import RespostaObjetiva +from src.respostadiscursiva import RespostaDiscursiva + + +class TentativaQuestionario: + def __init__(self, questionario, usuario, data_inicio=None, data_fim=None): + self._questionario = questionario + self._usuario = usuario + self._data_inicio = data_inicio or datetime.now() + self._data_fim = data_fim + self._respostas = [] # for Class Resposta + self._finalizado = False + + @property + def respostas(self): + return self._respostas + + @property + def usuario(self): + return self._usuario + + def registrar_resposta(self, indice_pergunta, valor): + pergunta = self._questionario.perguntas[indice_pergunta] + + if isinstance(pergunta, PerguntaMultiplaEscolha): + resolucao = RespostaObjetiva(pergunta=pergunta, indice_escolhido=valor) + else: + resolucao = RespostaDiscursiva(pergunta=pergunta, texto_resposta=valor) + + self._respostas.append(resolucao) + return resolucao + + def finalizar(self) -> tuple[float, str]: + # Finaliza a tentativa, calcula pontuação e gera feedback. + if self._finalizado: + return self.calcular_pontuacao(), "Tentativa já finalizada." + + self._data_fim = datetime.now() + self._finalizado = True + + pontuacao = self.calcular_pontuacao() + total_perguntas = len(self._questionario.perguntas) + feedback = f"Você obteve {pontuacao} de {total_perguntas} ponto(s)." + + return pontuacao, feedback + + def calcular_pontuacao(self) -> float: + total = 0.0 + for resposta in self._respostas: + total += resposta.calcular_pontuacao() + return total + + def is_finalizado(self) -> bool: + return True diff --git a/Guia4/src/test.py b/Guia4/src/test.py new file mode 100644 index 0000000..b31afe5 --- /dev/null +++ b/Guia4/src/test.py @@ -0,0 +1,6 @@ +from correcao import Correcao +from perguntadiscursiva import PerguntaDiscursiva + +p = PerguntaDiscursiva("O que é Python?", "Linguagem de programação interpretada") +result = Correcao.corrigir_discursiva(p, "Python é uma linguagem interpretada") +print(result) diff --git a/Guia4/tests/__init__.py b/Guia4/tests/__init__.py new file mode 100644 index 0000000..e69de29 From 313b62db6a45cd6fd8391a6cb7a95af3b0c692a7 Mon Sep 17 00:00:00 2001 From: serelepe Date: Fri, 12 Jun 2026 21:27:21 -0300 Subject: [PATCH 10/12] guia4 --- Guia4/.gitignore | 1 + Guia4/src/correcao.py | 5 ++- Guia4/src/llmservice.py | 11 ++---- Guia4/src/perguntamultiplaescolha.py | 26 ++++++++------ Guia4/src/respostadiscursiva.py | 29 +++++++++++----- Guia4/src/tentativaquestionario.py | 24 ++++++------- Guia4/src/test.py | 6 ---- Guia4/test_quiz.py | 51 ++++++++++++++++++++++++++++ 8 files changed, 105 insertions(+), 48 deletions(-) delete mode 100644 Guia4/src/test.py create mode 100644 Guia4/test_quiz.py diff --git a/Guia4/.gitignore b/Guia4/.gitignore index 4b3bf0c..8bf1b00 100644 --- a/Guia4/.gitignore +++ b/Guia4/.gitignore @@ -11,3 +11,4 @@ env/ .pytest_cache .coverage htmlcov/ +.env \ No newline at end of file diff --git a/Guia4/src/correcao.py b/Guia4/src/correcao.py index 1656888..d8025b1 100644 --- a/Guia4/src/correcao.py +++ b/Guia4/src/correcao.py @@ -1,6 +1,6 @@ from typing import Dict -from perguntadiscursiva import PerguntaDiscursiva -from llmservice import LLMService +from .perguntadiscursiva import PerguntaDiscursiva +from .llmservice import LLMService class Correcao: @@ -14,7 +14,6 @@ def corrigir_discursiva( @staticmethod def criar_prompt_correcao(pergunta: PerguntaDiscursiva, resposta_aluno: str) -> str: - # Método utilitário para visualizar/gerar o prompt sem chamar a API texto_pergunta = pergunta.texto resposta_esperada = pergunta.resposta_esperada or "Não informada" return f""" diff --git a/Guia4/src/llmservice.py b/Guia4/src/llmservice.py index 02f24eb..7ba7b61 100644 --- a/Guia4/src/llmservice.py +++ b/Guia4/src/llmservice.py @@ -2,12 +2,11 @@ import json from typing import Dict from groq import Groq - -from src.perguntadiscursiva import PerguntaDiscursiva +from .perguntadiscursiva import PerguntaDiscursiva class LLMService: - def __init__(self, api_key: str = None, model: str = "llama3-70b-8192"): + def __init__(self, api_key: str = None, model: str = "llama-3.3-70b-versatile"): self.api_key = api_key or os.environ.get("GROQ_API_KEY") if not self.api_key: raise ValueError( @@ -29,7 +28,6 @@ def corrigir_resposta( ) resposta_raw = response.choices[0].message.content resultado = json.loads(resposta_raw) - # Validação dos campos esperados if not all( k in resultado for k in ("correta", "pontuacao", "feedback", "explicacao") @@ -39,7 +37,6 @@ def corrigir_resposta( ) return resultado except Exception as e: - # Tratamento de erro: retorna estrutura padrão com falha return { "correta": False, "pontuacao": 0.0, @@ -50,8 +47,7 @@ def corrigir_resposta( def _montar_prompt(self, pergunta: PerguntaDiscursiva, resposta_aluno: str) -> str: texto_pergunta = pergunta.texto resposta_esperada = pergunta.resposta_esperada or "Não informada" - - prompt = f""" + return f""" Você é um corretor de questões discursivas. Pergunta: {texto_pergunta} @@ -69,4 +65,3 @@ def _montar_prompt(self, pergunta: PerguntaDiscursiva, resposta_aluno: str) -> s Não inclua texto adicional fora do JSON. """ - return prompt diff --git a/Guia4/src/perguntamultiplaescolha.py b/Guia4/src/perguntamultiplaescolha.py index 69aa2d5..e2561f9 100644 --- a/Guia4/src/perguntamultiplaescolha.py +++ b/Guia4/src/perguntamultiplaescolha.py @@ -1,28 +1,32 @@ -from typing import List, Tuple, Dict +from typing import List from src.alternativa import Alternativa from src.pergunta import Pergunta class PerguntaMultiplaEscolha(Pergunta): - def __init__(self, texto, explicacao_geral=None, alternativas: Alternativa = None): + def __init__( + self, texto, explicacao_geral=None, alternativas: List[Alternativa] = None + ): super().__init__(texto, explicacao_geral) - self._alternativa = alternativas + self._alternativas = alternativas or [] @property - def alternativa(self): - return self._alternativa + def alternativas(self): + return self._alternativas def validar_resposta(self, indice: int) -> bool: - v = self._alternativa[indice] - return v.correta + if 0 <= indice < len(self._alternativas): + return self._alternativas[indice].correta + return False def get_alternativa_correta(self) -> Alternativa: - for i in self._alternativa: - if i.correta is True: - return i + for alt in self._alternativas: + if alt.correta: + return alt + return None def get_tipo(self): return "multipla_escolha" def get_explicacao(self): - return "Python normalmente é interpretada." + return self._explicacao_geral or "Sem explicação adicional." diff --git a/Guia4/src/respostadiscursiva.py b/Guia4/src/respostadiscursiva.py index fa0f868..b830dd1 100644 --- a/Guia4/src/respostadiscursiva.py +++ b/Guia4/src/respostadiscursiva.py @@ -1,4 +1,4 @@ -from typing import List, Tuple, Dict +from typing import Dict, Optional from src.resposta import Resposta @@ -7,16 +7,29 @@ def __init__( self, pergunta, texto_resposta: str = None, - pontuacao_obtida=None, + correction_dict: Optional[Dict] = None, + pontuacao_obtida: float = None, ): self._texto_resposta = texto_resposta + self._feedback = None + self._explicacao = None - esta_correta = pergunta.validar_resposta(texto_resposta) + if correction_dict: + # Usa o resultado do LLM + esta_correta = correction_dict.get("correta", False) + pontuacao_obtida = correction_dict.get("pontuacao", 0.0) + self._feedback = correction_dict.get("feedback", "") + self._explicacao = correction_dict.get("explicacao", "") + else: + # Fallback: validação exata (para compatibilidade) + esta_correta = pergunta.validar_resposta(texto_resposta) super().__init__(pergunta, esta_correta, pontuacao_obtida) - def calcular_pontuacao(self): - if self.esta_correta: - return 1.0 - else: - return 0 + def calcular_pontuacao(self) -> float: + if self.pontuacao_obtida is not None: + return self.pontuacao_obtida + return 1.0 if self.esta_correta else 0.0 + + def get_feedback(self) -> str: + return self._feedback or "" diff --git a/Guia4/src/tentativaquestionario.py b/Guia4/src/tentativaquestionario.py index d9cd4f3..3a71f27 100644 --- a/Guia4/src/tentativaquestionario.py +++ b/Guia4/src/tentativaquestionario.py @@ -1,10 +1,9 @@ -from typing import List, Tuple, Dict from datetime import datetime - from src.perguntamultiplaescolha import PerguntaMultiplaEscolha - +from src.perguntadiscursiva import PerguntaDiscursiva from src.respostaobjetiva import RespostaObjetiva from src.respostadiscursiva import RespostaDiscursiva +from src.correcao import Correcao class TentativaQuestionario: @@ -13,7 +12,7 @@ def __init__(self, questionario, usuario, data_inicio=None, data_fim=None): self._usuario = usuario self._data_inicio = data_inicio or datetime.now() self._data_fim = data_fim - self._respostas = [] # for Class Resposta + self._respostas = [] self._finalizado = False @property @@ -29,14 +28,19 @@ def registrar_resposta(self, indice_pergunta, valor): if isinstance(pergunta, PerguntaMultiplaEscolha): resolucao = RespostaObjetiva(pergunta=pergunta, indice_escolhido=valor) + elif isinstance(pergunta, PerguntaDiscursiva): + # Usa o serviço LLM para corrigir a resposta discursiva + correction = Correcao.corrigir_discursiva(pergunta, valor) + resolucao = RespostaDiscursiva( + pergunta=pergunta, texto_resposta=valor, correction_dict=correction + ) else: - resolucao = RespostaDiscursiva(pergunta=pergunta, texto_resposta=valor) + raise TypeError(f"Tipo de pergunta não suportado: {type(pergunta)}") self._respostas.append(resolucao) return resolucao def finalizar(self) -> tuple[float, str]: - # Finaliza a tentativa, calcula pontuação e gera feedback. if self._finalizado: return self.calcular_pontuacao(), "Tentativa já finalizada." @@ -46,14 +50,10 @@ def finalizar(self) -> tuple[float, str]: pontuacao = self.calcular_pontuacao() total_perguntas = len(self._questionario.perguntas) feedback = f"Você obteve {pontuacao} de {total_perguntas} ponto(s)." - return pontuacao, feedback def calcular_pontuacao(self) -> float: - total = 0.0 - for resposta in self._respostas: - total += resposta.calcular_pontuacao() - return total + return sum(resp.calcular_pontuacao() for resp in self._respostas) def is_finalizado(self) -> bool: - return True + return self._finalizado diff --git a/Guia4/src/test.py b/Guia4/src/test.py deleted file mode 100644 index b31afe5..0000000 --- a/Guia4/src/test.py +++ /dev/null @@ -1,6 +0,0 @@ -from correcao import Correcao -from perguntadiscursiva import PerguntaDiscursiva - -p = PerguntaDiscursiva("O que é Python?", "Linguagem de programação interpretada") -result = Correcao.corrigir_discursiva(p, "Python é uma linguagem interpretada") -print(result) diff --git a/Guia4/test_quiz.py b/Guia4/test_quiz.py new file mode 100644 index 0000000..bb25539 --- /dev/null +++ b/Guia4/test_quiz.py @@ -0,0 +1,51 @@ +import os +from dotenv import load_dotenv +from src.perguntadiscursiva import PerguntaDiscursiva +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.alternativa import Alternativa +from src.questionario import Questionario + +load_dotenv() + +# Configure a chave da API (idealmente via variável de ambiente) + +# Criação do questionário +quiz = Questionario("Avaliação de Python") + +# Pergunta de múltipla escolha +alt1 = Alternativa("Compilada", False, "Python é interpretada.") +alt2 = Alternativa( + "Interpretada", True, "Correto! Python é uma linguagem interpretada." +) +mult = PerguntaMultiplaEscolha( + texto="Qual a natureza da linguagem Python?", + explicacao_geral="Python é interpretada, não compilada.", + alternativas=[alt1, alt2], +) +quiz.adicionar_pergunta(mult) + +# Pergunta discursiva +disc = PerguntaDiscursiva( + texto="Explique o que é um dicionário em Python.", + resposta_esperada="É uma estrutura de dados que armazena pares chave-valor.", +) +quiz.adicionar_pergunta(disc) + +# Simulação de tentativa +tentativa = quiz.criar_attempt("aluno@email.com") + +# Respostas +tentativa.registrar_resposta(0, 1) # índice 1 é a alternativa correta +tentativa.registrar_resposta( + 1, "Dicionário é uma coleção de pares chave-valor, mutável." +) + +# Finaliza e mostra resultado +pontos, feedback = tentativa.finalizar() +print(feedback) +print(f"Pontuação final: {pontos}") + +# Exibe detalhes da correção da discursiva (feedback do LLM) +resposta_disc = tentativa.respostas[1] +if hasattr(resposta_disc, "get_feedback"): + print(f"Feedback do LLM: {resposta_disc.get_feedback()}") From 5afb3c7af9ee20d1f15c378aac81a8e4dfdbca97 Mon Sep 17 00:00:00 2001 From: "D.Witalo" Date: Thu, 25 Jun 2026 13:33:09 -0300 Subject: [PATCH 11/12] =?UTF-8?q?Checando,=20revisando=20os=20Guias=20e=20?= =?UTF-8?q?configura=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Guia4/main.py | 55 +++++++++++++++++++++++++++++++-- Guia4/src/llmservice.py | 2 +- Guia4/src/resposta.py | 6 +++- Guia4/src/respostadiscursiva.py | 13 ++++++++ Guia4/src/respostaobjetiva.py | 28 ++++++++++++++++- Guia4/test_quiz.py | 51 ------------------------------ 6 files changed, 98 insertions(+), 57 deletions(-) delete mode 100644 Guia4/test_quiz.py diff --git a/Guia4/main.py b/Guia4/main.py index e9e667d..62bc151 100644 --- a/Guia4/main.py +++ b/Guia4/main.py @@ -1,8 +1,57 @@ -from Guia3.src import * +import os +from dotenv import load_dotenv +from src.perguntadiscursiva import PerguntaDiscursiva +from src.perguntamultiplaescolha import PerguntaMultiplaEscolha +from src.alternativa import Alternativa +from src.questionario import Questionario + def main(): - pass + # Carrega as variáveis de ambiente + load_dotenv() + + # Criação do questionário + quiz = Questionario("Avaliação de Python") + + # Pergunta de múltipla escolha + alt1 = Alternativa("Compilada", False, "Python é interpretada.") + alt2 = Alternativa( + "Interpretada", True, "Correto! Python é uma linguagem interpretada." + ) + mult = PerguntaMultiplaEscolha( + texto="Qual a natureza da linguagem Python?", + explicacao_geral="Python é interpretada, não compilada.", + alternativas=[alt1, alt2], + ) + quiz.adicionar_pergunta(mult) + + # Pergunta discursiva + disc = PerguntaDiscursiva( + texto="Explique o que é um dicionário em Python.", + resposta_esperada="É uma estrutura de dados que armazena pares chave-valor.", + ) + quiz.adicionar_pergunta(disc) + + # Simulação de tentativa + tentativa = quiz.criar_attempt("aluno@email.com") + + # Respostas + tentativa.registrar_resposta(0, 1) # índice 1 é a alternativa correta + tentativa.registrar_resposta( + 1, "Dicionário é uma coleção de pares chave-valor, mutável.\n" + ) + + # Finaliza e mostra resultado + pontos, feedback = tentativa.finalizar() + + print("\n--- Detalhes das respostas ---") + for resp in tentativa.respostas: + print(resp.descrever()) + print("-" * 40) + + print(feedback) + print(f"Pontuação final: {pontos}") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/Guia4/src/llmservice.py b/Guia4/src/llmservice.py index 7ba7b61..f6356f5 100644 --- a/Guia4/src/llmservice.py +++ b/Guia4/src/llmservice.py @@ -23,7 +23,7 @@ def corrigir_resposta( response = self.client.chat.completions.create( model=self.model, messages=[{"role": "user", "content": prompt}], - temperature=0.3, + temperature=1.8, response_format={"type": "json_object"}, ) resposta_raw = response.choices[0].message.content diff --git a/Guia4/src/resposta.py b/Guia4/src/resposta.py index 0b383cc..4caa792 100644 --- a/Guia4/src/resposta.py +++ b/Guia4/src/resposta.py @@ -1,4 +1,3 @@ -from typing import List, Tuple, Dict from abc import ABC, abstractmethod from src.pergunta import Pergunta @@ -17,3 +16,8 @@ def __init__( @abstractmethod def calcular_pontuacao(self) -> float: pass + + @abstractmethod + def descrever(self) -> str: + """Retorna um texto legível com a pergunta e a resposta dada.""" + pass diff --git a/Guia4/src/respostadiscursiva.py b/Guia4/src/respostadiscursiva.py index b830dd1..710fdf5 100644 --- a/Guia4/src/respostadiscursiva.py +++ b/Guia4/src/respostadiscursiva.py @@ -33,3 +33,16 @@ def calcular_pontuacao(self) -> float: def get_feedback(self) -> str: return self._feedback or "" + + def descrever(self) -> str: + status = "Correta" if self.esta_correta else "Incorreta" + linhas = [ + f"Pergunta: {self.pergunta.texto}", + f"Resposta dada: {self._texto_resposta}", + f"Avaliação: {status}", + ] + if self._feedback: + linhas.append(f"Feedback: {self._feedback}") + if self._explicacao: + linhas.append(f"Explicação: {self._explicacao}") + return "\n".join(linhas) diff --git a/Guia4/src/respostaobjetiva.py b/Guia4/src/respostaobjetiva.py index 45ee6f6..5e719b6 100644 --- a/Guia4/src/respostaobjetiva.py +++ b/Guia4/src/respostaobjetiva.py @@ -1,4 +1,3 @@ -from typing import List, Tuple, Dict from src.resposta import Resposta from src.alternativa import Alternativa from src.perguntamultiplaescolha import PerguntaMultiplaEscolha @@ -12,6 +11,11 @@ def __init__( alternativa_selecionada: Alternativa = None, ): self._indice_escolhido = indice_escolhido + + if alternativa_selecionada is None and indice_escolhido is not None: + alternativas = pergunta.alternativas + if 0 <= indice_escolhido < len(alternativas): + alternativa_selecionada = alternativas[indice_escolhido] self._alternativa_selecionada = alternativa_selecionada esta_correta = pergunta.validar_resposta(self._indice_escolhido) @@ -22,3 +26,25 @@ def calcular_pontuacao(self): return 1.0 else: return 0 + + def descrever(self) -> str: + if self._alternativa_selecionada is not None: + texto_escolhido = self._alternativa_selecionada.texto + else: + texto_escolhido = "Nenhuma alternativa selecionada" + + status = "Correta" if self.esta_correta else "Incorreta" + linhas = [ + f"Pergunta: {self.pergunta.texto}", + f"Resposta dada: {texto_escolhido} ({status})", + ] + + if not self.esta_correta: + alt_correta = self.pergunta.get_alternativa_correta() + if alt_correta is not None: + linhas.append(f"Resposta correta: {alt_correta.texto}") + explicacao = self.pergunta.get_explicacao() + if explicacao: + linhas.append(f"Explicação: {explicacao}") + + return "\n".join(linhas) diff --git a/Guia4/test_quiz.py b/Guia4/test_quiz.py deleted file mode 100644 index bb25539..0000000 --- a/Guia4/test_quiz.py +++ /dev/null @@ -1,51 +0,0 @@ -import os -from dotenv import load_dotenv -from src.perguntadiscursiva import PerguntaDiscursiva -from src.perguntamultiplaescolha import PerguntaMultiplaEscolha -from src.alternativa import Alternativa -from src.questionario import Questionario - -load_dotenv() - -# Configure a chave da API (idealmente via variável de ambiente) - -# Criação do questionário -quiz = Questionario("Avaliação de Python") - -# Pergunta de múltipla escolha -alt1 = Alternativa("Compilada", False, "Python é interpretada.") -alt2 = Alternativa( - "Interpretada", True, "Correto! Python é uma linguagem interpretada." -) -mult = PerguntaMultiplaEscolha( - texto="Qual a natureza da linguagem Python?", - explicacao_geral="Python é interpretada, não compilada.", - alternativas=[alt1, alt2], -) -quiz.adicionar_pergunta(mult) - -# Pergunta discursiva -disc = PerguntaDiscursiva( - texto="Explique o que é um dicionário em Python.", - resposta_esperada="É uma estrutura de dados que armazena pares chave-valor.", -) -quiz.adicionar_pergunta(disc) - -# Simulação de tentativa -tentativa = quiz.criar_attempt("aluno@email.com") - -# Respostas -tentativa.registrar_resposta(0, 1) # índice 1 é a alternativa correta -tentativa.registrar_resposta( - 1, "Dicionário é uma coleção de pares chave-valor, mutável." -) - -# Finaliza e mostra resultado -pontos, feedback = tentativa.finalizar() -print(feedback) -print(f"Pontuação final: {pontos}") - -# Exibe detalhes da correção da discursiva (feedback do LLM) -resposta_disc = tentativa.respostas[1] -if hasattr(resposta_disc, "get_feedback"): - print(f"Feedback do LLM: {resposta_disc.get_feedback()}") From 4bc19360c0a875a329bce4bebc18147202f0a382 Mon Sep 17 00:00:00 2001 From: "D.Witalo" Date: Thu, 25 Jun 2026 16:36:58 -0300 Subject: [PATCH 12/12] Adiciona projeto Guia5 (RPG Python) --- Guia5 | 1 + 1 file changed, 1 insertion(+) create mode 160000 Guia5 diff --git a/Guia5 b/Guia5 new file mode 160000 index 0000000..cf72303 --- /dev/null +++ b/Guia5 @@ -0,0 +1 @@ +Subproject commit cf72303c79f951659b35c7eef5183123cb00a736