diff --git a/.github/workflows/Java17CImaven.yml b/.github/workflows/Java17CImaven.yml index 038cd61b..c54287d4 100644 --- a/.github/workflows/Java17CImaven.yml +++ b/.github/workflows/Java17CImaven.yml @@ -34,7 +34,8 @@ jobs: - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 # Optional: Upload coverage report - - name: Check test coverage - uses: codecov/codecov-action@v4 + - name: codecov + uses: codecov/codecov-action@v5.4.0 with: token: ${{ secrets.CODECOV_TOKEN }} + slug: Nicop17/poolobject diff --git a/.github/workflows/codacy-coverage.yml b/.github/workflows/codacy-coverage.yml new file mode 100644 index 00000000..ac5394ea --- /dev/null +++ b/.github/workflows/codacy-coverage.yml @@ -0,0 +1,41 @@ +name: Codacy Coverage Reporter + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + run: mvn -B package --file pom.xml + + # Generar el reporte de cobertura de JaCoCo + - name: Run tests and generate coverage report + run: mvn test jacoco:report # Asegúrate de que se genere el reporte de cobertura + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + - name: Update dependency graph + uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 + + # Subir el reporte de cobertura a Codacy + - name: Run codacy-coverage-reporter + uses: codacy/codacy-coverage-reporter-action@v1.3.0 + with: + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + coverage-reports: target/site/jacoco-aggregate.xml # Ruta del reporte generado por JaCoCo + diff --git a/README.md b/README.md index 47c98e44..0af8a6f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ poolobject ========== +[![codecov](https://codecov.io/gh/Nicop17/poolobject/graph/badge.svg?token=D6XRI5RQA1)](https://codecov.io/gh/Nicop17/poolobject) +[![Java CI with Maven](https://github.com/Nicop17/poolobject/actions/workflows/Java17CImaven.yml/badge.svg)](https://github.com/Nicop17/poolobject/actions/workflows/Java17CImaven.yml) +[![codebeat badge](https://codebeat.co/badges/c0e21c3c-a6ab-4f31-a252-35818dd76e5a)](https://codebeat.co/projects/github-com-ibaimoya-poolobject-master) +[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-orange.svg)](https://opensource.org/licenses/GPL-2.0) +[![Wiki Home](https://img.shields.io/badge/Wiki-Home-blue)](https://github.com/Nicop17/poolobject/wiki) + + + Java code example of creational design pattern pool object @@ -10,3 +18,10 @@ Authors: - Carlos Lopez Nozal - Jesus Alonso Abad + +Students: + +- Ibai Moya +- Nicolás Pérez +- Juan García +- David Peñasco diff --git a/images/Ejemplo-error.png b/images/Ejemplo-error.png new file mode 100644 index 00000000..8e4ddbfa Binary files /dev/null and b/images/Ejemplo-error.png differ diff --git a/images/Imagen-cobertura.png b/images/Imagen-cobertura.png new file mode 100644 index 00000000..c53f6928 Binary files /dev/null and b/images/Imagen-cobertura.png differ diff --git a/images/Monitorizacion-commits.png b/images/Monitorizacion-commits.png new file mode 100644 index 00000000..17d9ca8f Binary files /dev/null and b/images/Monitorizacion-commits.png differ diff --git a/images/Numero-workflow.runs.png b/images/Numero-workflow.runs.png new file mode 100644 index 00000000..db749dd3 Binary files /dev/null and b/images/Numero-workflow.runs.png differ diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 00000000..ae3c1726 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/src/test/java/ubu/gii/dass/c01/ReusablePoolTest.java b/src/test/java/ubu/gii/dass/c01/ReusablePoolTest.java index 4e8c38d0..f7562983 100644 --- a/src/test/java/ubu/gii/dass/c01/ReusablePoolTest.java +++ b/src/test/java/ubu/gii/dass/c01/ReusablePoolTest.java @@ -1,63 +1,217 @@ -/** - * - */ package ubu.gii.dass.c01; -import static org.junit.jupiter.api.Assertions.assertTrue; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Disabled; - - +import org.junit.jupiter.api.Test; /** - * @author alumno - * + * Clase de pruebas unitarias. + * @author Ibai Moya + * @author David Peñasco + * @author Nicolás Pérez + * @author Juan García + * */ public class ReusablePoolTest { + private static ReusablePool pool; + private static final int MAX_RESOURCES = 2; + + /** + * Reinicia la instancia del pool antes de cada prueba. + * @throws Exception si ocurre un error al reiniciar la instancia. + */ + @BeforeEach + public void resetPool() throws Exception { + Field instanceField = ReusablePool.class.getDeclaredField("instance"); + instanceField.setAccessible(true); + instanceField.set(null, null); + pool = ReusablePool.getInstance(); + } + + + /** + * Libera todas las instancias del pool al finalizar todas las pruebas. + * @throws Exception si ocurre un error al liberar las instancias. + */ + @AfterAll + public static void tearDown() throws Exception { + List acquiredReusables = new ArrayList<>(); + /* Se adquieren todas las instancias disponibles del pool. */ + while (true) { + try { + acquiredReusables.add(pool.acquireReusable()); + } catch (NotFreeInstanceException e) { + break; + } + } + /* Se liberan las instancias obtenidas. */ + for (Reusable reusable : acquiredReusables) { + try { + pool.releaseReusable(reusable); + } catch (DuplicatedInstanceException e) { + System.err.println("Error al liberar una instancia: " + e.getMessage()); + } + } + } + + + /** + * Limpia el pool de reusables al finalizar cada prueba. + */ + @AfterEach + public void clearPools() { + List tempList = new ArrayList<>(); + try { + /* Acumula todas las instancias adquiribles. */ + while (true) { + tempList.add(pool.acquireReusable()); + } + } catch (NotFreeInstanceException e) { + /* Cuando no se pueden adquirir más instancias se sale del bucle. */ + } + /* Se devuelve todas las instancias acumuladas para restaurar el pool. */ + for (Reusable reusable : tempList) { + try { + pool.releaseReusable(reusable); + } catch (Exception ex) { + /* Se ignoran las excepciones durante la restauración del pool. */ + } + } + } + + + /** + * Método de prueba para la clase {@link ubu.gii.dass.c01.ReusablePool#getInstance()}. + */ + @Test + @DisplayName("testGetInstance") + public void testGetInstance() { + try { + ReusablePool pool1 = ReusablePool.getInstance(); + ReusablePool pool2 = ReusablePool.getInstance(); + assertNotNull(pool1, "La instancia pool1 no debería ser nula."); + assertNotNull(pool2, "La instancia pool2 no debería ser nula."); + assertSame(pool1, pool2, "Ambos deben ser idénticos."); + assertEquals(pool1, pool2, "Ambos deben ser iguales."); + } catch (Exception e) { + fail("Excepción en testGetInstance: " + e.getMessage()); + } + } + + /** + * Método de prueba para la clase {@link ubu.gii.dass.c01.ReusablePool#acquireReusable()}. + */ + @Test + @DisplayName("testAcquireReusable") + public void testAcquireReusable() { + /* Se almacenan las instancias adquiridas para posteriores comprobaciones. */ + Reusable[] reusables = new Reusable[MAX_RESOURCES]; + + /* Se adquieren el número máximo de instancias disponibles. */ + for (int i = 0; i < MAX_RESOURCES; i++) { + try { + reusables[i] = pool.acquireReusable(); + assertNotNull(reusables[i], "El reusable obtenido es nulo."); + } catch (NotFreeInstanceException e) { + fail("Error al adquirir una nueva instancia reusable: " + e.getMessage()); + } + } + + /* Se verifica que cada instancia adquirida es única. */ + for (int i = 0; i < MAX_RESOURCES - 1; i++) { + for (int j = i + 1; j < MAX_RESOURCES; j++) { + assertNotEquals(reusables[i], reusables[j], "Los reusables deben ser distintos."); + } + } + + /* Se comprueba que una nueva adquisición lanza la excepción esperada. */ + assertThrows(NotFreeInstanceException.class, () -> { + pool.acquireReusable(); + }, "No se lanzó NotFreeInstanceException al intentar adquirir más instancias."); + + /* Se prueba el caso límite: liberar una instancia y volver a adquirirla. */ + try { + pool.releaseReusable(reusables[0]); + Reusable reciclado = pool.acquireReusable(); + assertNotNull(reciclado, "El reusable reciclado es nulo."); + assertSame(reusables[0], reciclado, "El recurso debe ser reutilizado tras liberarlo."); + pool.releaseReusable(reciclado); + } catch (Exception e) { + fail("Error en el caso límite adicional de testAcquireReusable: " + e.getMessage()); + } + } + + + /** + * Método de prueba para la clase {@link ubu.gii.dass.c01.ReusablePool#releaseReusable(ubu.gii.dass.c01.Reusable)}. + */ + @Test + @DisplayName("testReleaseReusable") + public void testReleaseReusable() { + try { + ReusablePool pool = ReusablePool.getInstance(); + Reusable obj1 = pool.acquireReusable(); + assertNotNull(obj1, "El reusable no debería ser nulo."); + pool.releaseReusable(obj1); + + Reusable obj2 = pool.acquireReusable(); + assertSame(obj1, obj2, "El reusable debe ser reutilizado."); + pool.releaseReusable(obj2); + + /* Se prueba el caso límite: liberar null no debe lanzar excepción. */ + assertDoesNotThrow(() -> pool.releaseReusable(null), "releaseReusable(null) no debe lanzar excepción."); + + /* Se prueba el caso límite: liberar un objeto no gestionado por el pool no debe lanzar excepción. */ + Reusable fakeReusable = new Reusable(); + assertDoesNotThrow(() -> pool.releaseReusable(fakeReusable), "releaseReusable(fakeReusable) no debe lanzar excepción."); + + /* Se prueba el caso límite: intentar liberar nuevamente el mismo objeto debe lanzar excepción. */ + assertThrows(DuplicatedInstanceException.class, () -> { + pool.releaseReusable(obj2); + }, "No se lanzó DuplicatedInstanceException al intentar liberar dos veces el mismo objeto."); + } catch (Exception e) { + fail("Excepción en testReleaseReusable: " + e.getMessage()); + } + } + + + /** + * Método de prueba para la clase {@link ubu.gii.dass.c01.Client#main()}. + */ + @Test + @DisplayName("testClientMain") + public void testClientMain() { + + /* Se valida que Client se inicializa correctamente y que su método main se ejecute sin incidencias. */ + Client clientInstance = new Client(); + assertNotNull(clientInstance, "Se requería que la instancia de Client no fuese nula."); + assertDoesNotThrow(() -> Client.main(new String[]{}), "La ejecución de Client.main no debió lanzar excepción."); + } + + + /** + * Método de prueba para la clase {@link ubu.gii.dass.c01.Reusable#util()}. + */ + @Test + @DisplayName("testUtilMethod") + public void testUtilMethod() { - - @BeforeAll - public static void setUp(){ - } - - - @AfterAll - public static void tearDown() throws Exception { - } - - /** - * Test method for {@link ubu.gii.dass.c01.ReusablePool#getInstance()}. - */ - @Test - @DisplayName("testGetInstance") - @Disabled("Not implemented yet") - public void testGetInstance() { - - } - - /** - * Test method for {@link ubu.gii.dass.c01.ReusablePool#acquireReusable()}. - */ - @Test - @DisplayName("testAcquireReusable") - @Disabled("Not implemented yet") - - public void testAcquireReusable() { - - } - - /** - * Test method for {@link ubu.gii.dass.c01.ReusablePool#releaseReusable(ubu.gii.dass.c01.Reusable)}. - */ - @Test - @DisplayName("testReleaseReusable") - @Disabled("Not implemented yet") - public void testReleaseReusable() { - - } - -} + /* Se comprueba que el método util() retorne valores diferentes para instancias distintas. */ + Reusable reusableA = new Reusable(); + Reusable reusableB = new Reusable(); + assertNotEquals(reusableA.util(), reusableB.util(), "Se esperaba que las salidas de util() fueran diferentes."); + } +} \ No newline at end of file