diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/SOLUCION.md b/SOLUCION.md new file mode 100644 index 0000000..1ae0835 --- /dev/null +++ b/SOLUCION.md @@ -0,0 +1,17 @@ +# Ignacio González Pozo - igonzalezp@gmail.com + +Fase A - Escenarios de prueba whatsapp + +Herramientas: Gherkin + +Ubicacion: +src/test/java/challenge.faseA + + +Fase B - Desarrollo Kata09: Back to the Checkout + +Herramientas: Java - junit - Maven + +Ubicacion: +src/java/challenge.faseB +src/test/java/challenge.faseB diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0dcdf2a --- /dev/null +++ b/pom.xml @@ -0,0 +1,76 @@ + + + + 4.0.0 + + challenge + qachallenge + 1.0-SNAPSHOT + + qachallenge + + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/src/main/java/challenge/faseB/CheckOut.java b/src/main/java/challenge/faseB/CheckOut.java new file mode 100644 index 0000000..d62981b --- /dev/null +++ b/src/main/java/challenge/faseB/CheckOut.java @@ -0,0 +1,110 @@ +package challenge.faseB; + +import java.text.DecimalFormat; +import java.util.Map; +import java.util.TreeMap; + +/** + * Contiene carro de compra y aplica descuentos de acuerdo a promociones actuales + */ + +public class CheckOut { + //Items en carro de compras + private Map checkedItems = new TreeMap<>(); + + //Valor total a pagar + private Double totalPrice = 0.0; + + //Recibe promociones actuales + private Map promotionRules; + + //Formatea a dos decimales + private DecimalFormat decimal = new DecimalFormat("#.##"); + + public CheckOut(Map promotionRules) { + this.promotionRules = promotionRules; + } + + public Double getTotalPrice () { + return this.totalPrice; + } + + /** + * Calcula total a pagar y aplica promociones + */ + public void totalCalculator () { + //Total sin descuentos + System.out.println("TOTAL: " + decimal.format(totalPrice)); + + //Aplica promociones y descuentos en caso de aplicar + applyPromotions(); + + System.out.println(); + //Total con descuentos + System.out.println("TOTAL PRICE: " + decimal.format(totalPrice)); + } + /** + * Añade los items al carro + */ + public void checkItem (String item) { + if(checkedItems.containsKey(item)) + checkedItems.put(item, checkedItems.get(item) + 1); + else + { + checkedItems.put(item, 1); + } + //Total hasta al momento por cada item añadido, sin descuentos + totalPrice = totalPrice + promotionRules.get(item).getUnitPrice(); + } + /** + * Aplica promociones al carro de compra + */ + private void applyPromotions() { + //Iteracion por items en carro de compras + for (Map.Entry entry : checkedItems.entrySet()) { + + //Verifica si item en carro de compras tiene promocion + if (promotionRules.containsKey(entry.getKey()) && + promotionRules.get(entry.getKey()).getPromotionRequirement() != null) { + + //Valida tipo promocion a aplicar, en caso de existir mas promociones + if (promotionRules.get(entry.getKey()).getPromotionType().equals("MOREFORLESS")) { + moreForLess(entry); + } + } + } + } + /** + * Aplica reglas de promocion MOREFORLESS + */ + private void moreForLess (Map.Entry entry) { + //Verifica si cumple requisito de promocion + if (promotionRules.get(entry.getKey()).getPromotionRequirement() <= entry.getValue()) { + + //Calcula valor sin promocion, cantidad del item * precio unitario + Double sumNoPromo = entry.getValue() * promotionRules.get(entry.getKey()).getUnitPrice(); + + //Cantidad veces se aplica valor promocion + Integer timesPromo = entry.getValue() / promotionRules.get(entry.getKey()).getPromotionRequirement(); + //Cantidad items sin promocion + Integer itemsNoPromo = (entry.getValue() % promotionRules.get(entry.getKey()).getPromotionRequirement()); + + //Calcula valor total item aplicando promocion + Double sumPromo = (timesPromo * promotionRules.get(entry.getKey()).getPromotionPrice()) + + (itemsNoPromo * promotionRules.get(entry.getKey()).getUnitPrice()); + + //Calcula descuento aplicado al item, total sin promocion - total con promocion + Double discount = sumNoPromo - sumPromo; + + System.out.println("MOREFORLESS Saved " + decimal.format(discount) + " on item " +entry.getKey()); + + applyDiscount(discount); + } + } + /** + * Aplica descuento al total a pagar + */ + public void applyDiscount (Double discount) { + totalPrice = totalPrice - discount; + } +} \ No newline at end of file diff --git a/src/main/java/challenge/faseB/Promotion.java b/src/main/java/challenge/faseB/Promotion.java new file mode 100644 index 0000000..ef42510 --- /dev/null +++ b/src/main/java/challenge/faseB/Promotion.java @@ -0,0 +1,36 @@ +package challenge.faseB; + +/** + * Clase para asignacion de promociones a producto + * tipoPromocion, precioPromocion, requisitoPromocion + */ + +public class Promotion { + private String promotionType; + private Double promotionPrice; + private Integer promotionRequirement; + private Double unitPrice; + + public Promotion(String promotionType, Double promotionPrice, Integer promotionRequirement, Double unitPrice) { + this.promotionType = promotionType; + this.promotionPrice = promotionPrice; + this.promotionRequirement = promotionRequirement; + this.unitPrice = unitPrice; + } + + public String getPromotionType(){ + return this.promotionType; + } + + public Integer getPromotionRequirement(){ + return this.promotionRequirement; + } + + public Double getPromotionPrice(){ + return this.promotionPrice; + } + + public Double getUnitPrice(){ + return this.unitPrice; + } +} diff --git a/src/main/java/challenge/faseB/PromotionLibrary.java b/src/main/java/challenge/faseB/PromotionLibrary.java new file mode 100644 index 0000000..eb0d503 --- /dev/null +++ b/src/main/java/challenge/faseB/PromotionLibrary.java @@ -0,0 +1,31 @@ +package challenge.faseB; + +import java.util.Map; +import java.util.TreeMap; + +/** + * Contiene promociones actuales + * Item en Promocion, tipoPromocion, precioPromocion, requisitoPromocion + * + * Precios unitarios por item + * "A", 50 + * "B", 30 + * "C", 20 + * "D", 15 + */ + +public class PromotionLibrary { + + public static Map promotionIndex = new TreeMap(); + + static { + promotionIndex.put("A", + new Promotion("MOREFORLESS", 130.0,3, 50.0)); + promotionIndex.put("B", + new Promotion("MOREFORLESS", 45.0,2, 30.0)); + promotionIndex.put("C", + new Promotion("MOREFORLESS", null,null, 20.0)); + promotionIndex.put("D", + new Promotion("MOREFORLESS", null,null, 15.0)); + } +} diff --git a/src/main/java/challenge/faseB/Runner.java b/src/main/java/challenge/faseB/Runner.java new file mode 100644 index 0000000..c65f617 --- /dev/null +++ b/src/main/java/challenge/faseB/Runner.java @@ -0,0 +1,41 @@ +package challenge.faseB; + +/** + * Ignacio González Pozo - igonzalezp@gmail.com + * Precios unitarios por item + * "A",50 + * "B",30 + * "C",20 + * "D",15 + */ +public class Runner +{ + public static void main( String[] args ) + { + + CheckOut co = new CheckOut(PromotionLibrary.promotionIndex); + + //Valores para posibles items: A - B - C - D + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("D"); + co.checkItem("C"); + co.checkItem("D"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("B"); + co.checkItem("B"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("D"); + co.checkItem("C"); + co.checkItem("D"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("B"); + co.checkItem("B"); + co.totalCalculator(); + } +} diff --git a/src/test/java/challenge/faseA/enviar-documento.feature b/src/test/java/challenge/faseA/enviar-documento.feature new file mode 100644 index 0000000..3dbfe8a --- /dev/null +++ b/src/test/java/challenge/faseA/enviar-documento.feature @@ -0,0 +1,47 @@ +Feature: Enviar documentos + Como usuario de la aplicación whatsapp de telefono Android + quiero adjuntar documentos a una conversacion + para compartir archivos que tengo en el telefono + + #Given - Dado que + #When - Cuando + #Then - Entonces + + Background: + Given me encuentro en la conversacion "chat xyz" + + Scenario Outline: Adjuntar un documento a la conversacion + When se selecciona la opcion de adjuntar documento + And envio un + Then se muestra recuadro que indica nombre documento y progreso de envio + And al finalizar el envio permite descargar el documento + + Examples: #documento: formato de documento a adjuntar + | documento | + | pdf | + | doc | + | rar | + + + Scenario Outline: Cancelar envio de documento a la conversacion + When se selecciona la opcion de adjuntar documento + And envio un + And presiona el progreso del envio para cancelarlo + Then el envio se cancela y permite en el mensaje volver a enviarlo + + Examples: #documento: formato de documento a adjuntar + | documento | + | rar | + + + Scenario: Adjuntar mas de un documento a la conversacion + When se selecciona la opcion de adjuntar documento + And envio mas de un documento + Then se muestra recuadro que indica nombre y progreso del envio en cada uno + And al finalizar el envio permite descargar cada documento + + + Scenario: Adjuntar documento superior a 99MB + When se selecciona la opcion de adjuntar documento + And se envia un documento superior a 99MB + Then se cancela el envio con mensaje de error "mensaje" \ No newline at end of file diff --git a/src/test/java/challenge/faseA/silenciar-conversacion.feature b/src/test/java/challenge/faseA/silenciar-conversacion.feature new file mode 100644 index 0000000..f9bb7e5 --- /dev/null +++ b/src/test/java/challenge/faseA/silenciar-conversacion.feature @@ -0,0 +1,68 @@ +Feature: Silenciar conversacion + Como usuario de la aplicación whatsapp de telefono Android + quiero silenciar una conversacion + para dejar de recibir notificaciones de audio y/o por pantalla cada vez que recibo un mensaje + + #Given - Dado que + #When - Cuando + #Then - Entonces + + Background: + Given la aplicacion whatsapp esta en la pantalla inicial + + Scenario Outline: Silenciar conversacion desde pantalla inicial + When selecciona la conversacion "chat xyz" y presiona el icono "Silenciar" + And configura rango de tiempo y notificaciones en pantalla + Then nuevos mensajes son silenciados y se muestran en pantalla + And la conversacion queda silenciada mostrando el icono sin sonido + + Examples: #tiempo: rango de tiempo | 8H <8 horas> - 1W <1 semana> - 1Y <1 año> + #mostrar: muestra por pantalla notificaciones | SI - NO + | tiempo | mostrar | + | 8H | SI | + | 1W | NO | + | 1Y | SI | + + + Scenario Outline: Silenciar mas de una conversacion en pantalla principal + When selecciona mas de una conversacion "chat xyz" "chat abc" y presiona el icono "Silenciar" + And configura rango de tiempo y notificaciones en pantalla + Then nuevos mensajes son silenciados y se muestran en pantalla + And las conversaciones quedan silenciadas mostrando el icono sin sonido + + Examples: #tiempo: rango de tiempo | 8H <8 horas> - 1W <1 semana> - 1Y <1 año> + #mostrar: muestra por pantalla notificaciones | SI - NO + | tiempo | mostrar | + | 8H | SI | + | 1W | SI | + | 1Y | NO | + + + Scenario Outline: Silenciar conversacion mediante menu buscar + Given se ha buscado la conversacion "chat xyz" a silenciar + When desplega menu de opciones y presiona "Silenciar notificaciones" + And configura rango de tiempo y notificaciones en pantalla + Then nuevos mensajes son silenciados y se muestran en pantalla + And en menu de opciones aparece "Desactivar silencio de notificaciones" + + Examples: #tiempo: rango de tiempo | 8H <8 horas> - 1W <1 semana> - 1Y <1 año> + #mostrar: muestra por pantalla notificaciones | SI - NO + | tiempo | mostrar | + | 8H | SI | + | 1W | NO | + | 1Y | NO | + + + Scenario Outline: Silenciar conversacion al interior de conversacion + Given me encuentro al interior de la conversacion "chat xyz" a silenciar + When desplega menu de opciones de conversacion y selecciona "Silenciar notificaciones" + And configura rango de tiempo y notificaciones en pantalla + Then nuevos mensajes son silenciados y se muestran en pantalla + And en opciones de conversacion aparece "Desactivar silencio de notificaciones" + + Examples: #tiempo: rango de tiempo | 8H <8 horas> - 1W <1 semana> - 1Y <1 año> + #mostrar: muestra por pantalla notificaciones | SI - NO + | tiempo | mostrar | + | 8H | NO | + | 1W | SI | + | 1Y | SI | \ No newline at end of file diff --git a/src/test/java/challenge/faseB/CheckOutTest.java b/src/test/java/challenge/faseB/CheckOutTest.java new file mode 100644 index 0000000..111e797 --- /dev/null +++ b/src/test/java/challenge/faseB/CheckOutTest.java @@ -0,0 +1,73 @@ +package challenge.faseB; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Contiene promociones actuales + * Item en Promocion, tipoPromocion, precioPromocion, requisitoPromocion + * + * Precios unitarios por item + * "A", 50 + * "B", 30 + * "C", 20 + * "D", 15 + */ +public class CheckOutTest +{ + + @Test + public void checkItemTest() + { + CheckOut co = new CheckOut(PromotionLibrary.promotionIndex); + + assertEquals(0.0, co.getTotalPrice(), 0.2); + + //Valores para posibles items: A - B - C - D + co.checkItem("A"); + assertEquals(50.0, co.getTotalPrice(), 0.2); + + co.checkItem("A"); + assertEquals(100.0, co.getTotalPrice(), 0.2); + + co.checkItem("A"); + assertEquals(150.0, co.getTotalPrice(), 0.2); + + co.checkItem("D"); + assertEquals(165.0, co.getTotalPrice(), 0.2); + + co.checkItem("C"); + assertEquals(185.0, co.getTotalPrice(), 0.2); + + co.checkItem("B"); + assertEquals(215.0, co.getTotalPrice(), 0.2); + + co.checkItem("B"); + assertEquals(245.0, co.getTotalPrice(), 0.2); + } + + @Test + public void totalCalculatorTest() + { + CheckOut co = new CheckOut(PromotionLibrary.promotionIndex); + + //Valores para posibles items: A - B - C - D + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("D"); + co.checkItem("C"); + co.checkItem("B"); + co.checkItem("B"); + co.checkItem("B"); + co.checkItem("D"); + co.checkItem("A"); + co.checkItem("A"); + co.checkItem("B"); + + co.totalCalculator(); + + assertEquals(370.0, co.getTotalPrice(), 0.2);; + } +}