diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml
new file mode 100644
index 000000000..8fb587348
--- /dev/null
+++ b/.github/workflows/github-actions.yml
@@ -0,0 +1,15 @@
+name: CI for Java Invoice
+on: [push]
+jobs:
+ test:
+ name: Unit tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK
+ uses: actions/setup-java@v2
+ with:
+ java-version: '17'
+ distribution: 'adopt'
+ - name: Test
+ run: mvn test
\ No newline at end of file
diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml
new file mode 100644
index 000000000..d1f49a71a
--- /dev/null
+++ b/.github/workflows/qodana_code_quality.yml
@@ -0,0 +1,40 @@
+#-------------------------------------------------------------------------------#
+# Discover all capabilities of Qodana in our documentation #
+# https://www.jetbrains.com/help/qodana/about-qodana.html #
+#-------------------------------------------------------------------------------#
+
+name: Qodana
+on:
+ workflow_dispatch:
+ pull_request:
+ push:
+ branches:
+ - master
+ - tdd
+
+jobs:
+ qodana:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+ checks: write
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - name: 'Qodana Scan'
+ uses: JetBrains/qodana-action@v2026.1
+ env:
+ QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
+ with:
+ # When pr-mode is set to true, Qodana analyzes only the files that have been changed
+ pr-mode: false
+ use-caches: true
+ post-pr-comment: true
+ use-annotations: true
+ # Upload Qodana results (SARIF, other artifacts, logs) as an artifact to the job
+ upload-result: false
+ # quick-fixes available in Ultimate and Ultimate Plus plans
+ push-fixes: 'none'
\ No newline at end of file
diff --git a/config/checkstyle.xml b/config/checkstyle.xml
new file mode 100644
index 000000000..24335bb6c
--- /dev/null
+++ b/config/checkstyle.xml
@@ -0,0 +1,295 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/effective-pom.xml b/effective-pom.xml
new file mode 100644
index 000000000..21a89f947
--- /dev/null
+++ b/effective-pom.xml
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 4.0.0
+ pl.edu.agh.mwo.hellomaven
+ hello-maven
+ 1.0.0-SNAPSHOT
+
+ 17
+ 17
+ 3.2.0
+ UTF-8
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 6.0.3
+ test
+
+
+
+
+
+ false
+
+ central
+ Central Repository
+ https://repo.maven.apache.org/maven2
+
+
+
+
+
+ false
+
+ central
+ Central Repository
+ https://repo.maven.apache.org/maven2
+
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/src/main/java
+ /Users/olenka/Desktop/java-invoice-tdd/src/main/scripts
+ /Users/olenka/Desktop/java-invoice-tdd/src/test/java
+ /Users/olenka/Desktop/java-invoice-tdd/target/classes
+ /Users/olenka/Desktop/java-invoice-tdd/target/test-classes
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/src/main/resources
+
+
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/src/test/resources
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/target
+ hello-maven-1.0.0-SNAPSHOT
+
+
+
+ maven-antrun-plugin
+ 3.1.0
+
+
+ maven-assembly-plugin
+ 3.7.1
+
+
+ maven-dependency-plugin
+ 3.7.0
+
+
+ maven-release-plugin
+ 3.0.1
+
+
+
+
+
+ maven-jar-plugin
+ 3.2.0
+
+
+ default-jar
+ package
+
+ jar
+
+
+
+
+ true
+ pl.edu.agh.mwo.hellomaven.App
+
+
+
+
+
+
+
+
+ true
+ pl.edu.agh.mwo.hellomaven.App
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.2.1
+
+ pl.edu.agh.mwo.hellomaven.App
+
+
+
+ maven-clean-plugin
+ 3.2.0
+
+
+ default-clean
+ clean
+
+ clean
+
+
+
+
+
+ maven-resources-plugin
+ 3.4.0
+
+
+ default-testResources
+ process-test-resources
+
+ testResources
+
+
+
+ default-resources
+ process-resources
+
+ resources
+
+
+
+
+
+ maven-compiler-plugin
+ 3.15.0
+
+
+ default-compile
+ compile
+
+ compile
+
+
+
+ default-testCompile
+ test-compile
+
+ testCompile
+
+
+
+
+
+ maven-surefire-plugin
+ 3.5.4
+
+
+ default-test
+ test
+
+ test
+
+
+
+
+
+ maven-install-plugin
+ 3.1.4
+
+
+ default-install
+ install
+
+ install
+
+
+
+
+
+ maven-deploy-plugin
+ 3.1.4
+
+
+ default-deploy
+ deploy
+
+ deploy
+
+
+
+
+
+ maven-site-plugin
+ 3.12.1
+
+
+ default-site
+ site
+
+ site
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/target/site
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+
+
+
+
+
+ default-deploy
+ site-deploy
+
+ deploy
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/target/site
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+
+
+
+
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/target/site
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+
+
+
+
+
+
+
+ /Users/olenka/Desktop/java-invoice-tdd/target/site
+
+
diff --git a/pom.xml b/pom.xml
index 2d40c3e8a..411c4d9c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,11 +19,33 @@
org.apache.maven.plugins
- maven-compiler-plugin
+ maven-checkstyle-plugin
+ 3.3.1
- 17
- 17
-
+
+ ${project.basedir}/config/checkstyle.xml
+
+ true
+ true
+ false
+
+
+
+ validate
+ validate
+
+ check
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.13.0
+ 17
+ 17
+
@@ -32,7 +54,7 @@
junit
junit
- 4.12
+ 4.13.2
test
@@ -40,5 +62,11 @@
hamcrest-all
1.3
+
+ org.hamcrest
+ hamcrest
+ 2.2
+ test
+
-
+
\ No newline at end of file
diff --git a/qodana.yaml b/qodana.yaml
new file mode 100644
index 000000000..fcaa9673e
--- /dev/null
+++ b/qodana.yaml
@@ -0,0 +1,49 @@
+#-------------------------------------------------------------------------------#
+# Qodana analysis is configured by qodana.yaml file #
+# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
+#-------------------------------------------------------------------------------#
+
+#################################################################################
+# WARNING: Do not store sensitive information in this file, #
+# as its contents will be included in the Qodana report. #
+#################################################################################
+version: "1.0"
+
+#Specify inspection profile for code analysis
+profile:
+ name: qodana.starter
+
+#Enable inspections
+#include:
+# - name:
+
+#Disable inspections
+#exclude:
+# - name:
+# paths:
+# -
+
+projectJDK: "26" #(Applied in CI/CD pipeline)
+
+#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
+#bootstrap: sh ./prepare-qodana.sh
+
+#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
+#plugins:
+# - id: #(plugin id can be found at https://plugins.jetbrains.com)
+
+# Quality gate. Will fail the CI/CD pipeline if any condition is not met
+# severityThresholds - configures maximum thresholds for different problem severities
+# testCoverageThresholds - configures minimum code coverage on a whole project and newly added code
+# Code Coverage is available in Ultimate and Ultimate Plus plans
+#failureConditions:
+# severityThresholds:
+# any: 15
+# critical: 5
+# testCoverageThresholds:
+# fresh: 70
+# total: 50
+
+#Qodana supports other languages, for example, Python, JavaScript, TypeScript, Go, C#, PHP
+#For all supported languages see https://www.jetbrains.com/help/qodana/linters.html
+linter: jetbrains/qodana-jvm-community:2026.1
diff --git a/src/main/java/pl/edu/agh/mwo/invoice/Invoice.java b/src/main/java/pl/edu/agh/mwo/invoice/Invoice.java
index 3fd0def7a..9df7f3e97 100644
--- a/src/main/java/pl/edu/agh/mwo/invoice/Invoice.java
+++ b/src/main/java/pl/edu/agh/mwo/invoice/Invoice.java
@@ -1,62 +1,87 @@
package pl.edu.agh.mwo.invoice;
import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import pl.edu.agh.mwo.invoice.product.Product;
public class Invoice {
- private Map products = new HashMap<>();
+ private static int nextNumber = 1;
+ private final int number;
+ private final Map products = new LinkedHashMap();
- public void addProduct(Product product) {
- addProduct(product, 1);
+ public Invoice() {
+ number = nextNumber++;
}
- public void addProduct(Product product, Integer quantity) {
-
- if (product == null) {
- throw new IllegalArgumentException("Product cannot be null");
- }
-
- if (quantity == null || quantity <= 0) {
- throw new IllegalArgumentException("Quantity must be positive");
- }
- products.put(product, quantity);
+ public int getNumber() {
+ return number;
}
- public BigDecimal getSubtotal() {
+ public String getPrintout() {
+ StringBuilder printout = new StringBuilder();
+ String separator = System.lineSeparator();
- BigDecimal subtotal = BigDecimal.ZERO;
+ printout.append("Numer faktury: ")
+ .append(number)
+ .append(separator);
for (Map.Entry entry : products.entrySet()) {
Product product = entry.getKey();
Integer quantity = entry.getValue();
- subtotal = subtotal.add(
- product.getPrice().multiply(BigDecimal.valueOf(quantity)));
+ printout.append(product.getName())
+ .append(", ")
+ .append(quantity)
+ .append(" szt., ")
+ .append(product.getPrice())
+ .append(separator);
}
- return subtotal;
+
+ printout.append("Liczba pozycji: ")
+ .append(products.size());
+
+ return printout.toString();
}
- public BigDecimal getTax() {
- BigDecimal tax = BigDecimal.ZERO;
- for (Map.Entry entry : products.entrySet()) {
- Product product = entry.getKey();
- Integer quantity = entry.getValue();
+ public void addProduct(Product product) {
+ addProduct(product, 1);
+ }
+
+ public void addProduct(Product product, Integer quantity) {
+ if (product == null || quantity <= 0) {
+ throw new IllegalArgumentException();
+ }
+
+ Integer currentQuantity = products.get(product);
- BigDecimal productTax =
- product.getPrice()
- .multiply(product.getTaxPercent())
- .multiply(BigDecimal.valueOf(quantity));
- tax = tax.add(productTax);
+ if (currentQuantity == null) {
+ products.put(product, quantity);
+ } else {
+ products.put(product, currentQuantity + quantity);
}
- return tax;
}
- public BigDecimal getTotal() {
- return getSubtotal().add(getTax());
+ public BigDecimal getNetTotal() {
+ BigDecimal totalNet = BigDecimal.ZERO;
+ for (Product product : products.keySet()) {
+ BigDecimal quantity = new BigDecimal(products.get(product));
+ totalNet = totalNet.add(product.getPrice().multiply(quantity));
+ }
+ return totalNet;
+ }
+
+ public BigDecimal getTaxTotal() {
+ return getGrossTotal().subtract(getNetTotal());
+ }
+
+ public BigDecimal getGrossTotal() {
+ BigDecimal totalGross = BigDecimal.ZERO;
+ for (Product product : products.keySet()) {
+ BigDecimal quantity = new BigDecimal(products.get(product));
+ totalGross = totalGross.add(product.getPriceWithTax().multiply(quantity));
+ }
+ return totalGross;
}
}
diff --git a/src/main/java/pl/edu/agh/mwo/invoice/package-info.java b/src/main/java/pl/edu/agh/mwo/invoice/package-info.java
new file mode 100644
index 000000000..05fbd5def
--- /dev/null
+++ b/src/main/java/pl/edu/agh/mwo/invoice/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides classes for creating and managing invoices.
+ */
+package pl.edu.agh.mwo.invoice;
\ No newline at end of file
diff --git a/src/main/java/pl/edu/agh/mwo/invoice/product/BottleOfWine.java b/src/main/java/pl/edu/agh/mwo/invoice/product/BottleOfWine.java
new file mode 100644
index 000000000..933fd3e05
--- /dev/null
+++ b/src/main/java/pl/edu/agh/mwo/invoice/product/BottleOfWine.java
@@ -0,0 +1,18 @@
+package pl.edu.agh.mwo.invoice.product;
+
+import java.math.BigDecimal;
+
+public class BottleOfWine extends OtherProduct {
+
+ private static final BigDecimal EXCISE_DUTY =
+ new BigDecimal("5.56");
+
+ public BottleOfWine(String name, BigDecimal price) {
+ super(name, price);
+ }
+
+ @Override
+ public BigDecimal getPriceWithTax() {
+ return super.getPriceWithTax().add(EXCISE_DUTY);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/pl/edu/agh/mwo/invoice/product/FuelCanister.java b/src/main/java/pl/edu/agh/mwo/invoice/product/FuelCanister.java
new file mode 100644
index 000000000..7b24b312b
--- /dev/null
+++ b/src/main/java/pl/edu/agh/mwo/invoice/product/FuelCanister.java
@@ -0,0 +1,18 @@
+package pl.edu.agh.mwo.invoice.product;
+
+import java.math.BigDecimal;
+
+public class FuelCanister extends TaxFreeProduct {
+
+ private static final BigDecimal EXCISE_DUTY =
+ new BigDecimal("5.56");
+
+ public FuelCanister(String name, BigDecimal price) {
+ super(name, price);
+ }
+
+ @Override
+ public BigDecimal getPriceWithTax() {
+ return super.getPriceWithTax().add(EXCISE_DUTY);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/pl/edu/agh/mwo/invoice/product/Product.java b/src/main/java/pl/edu/agh/mwo/invoice/product/Product.java
index ee782a311..6ceba79d1 100644
--- a/src/main/java/pl/edu/agh/mwo/invoice/product/Product.java
+++ b/src/main/java/pl/edu/agh/mwo/invoice/product/Product.java
@@ -1,6 +1,7 @@
package pl.edu.agh.mwo.invoice.product;
import java.math.BigDecimal;
+import java.util.Objects;
public abstract class Product {
private final String name;
@@ -10,15 +11,10 @@ public abstract class Product {
private final BigDecimal taxPercent;
protected Product(String name, BigDecimal price, BigDecimal tax) {
-
- if (name == null || name.isBlank()) {
- throw new IllegalArgumentException("Product name cannot be null or blank");
- }
-
- if (price == null || price.compareTo(BigDecimal.ZERO) < 0) {
- throw new IllegalArgumentException("Product price cannot be null or negative");
+ if (name == null || name.equals("") || price == null || tax == null || tax.compareTo(new BigDecimal(0)) < 0
+ || price.compareTo(new BigDecimal(0)) < 0) {
+ throw new IllegalArgumentException();
}
-
this.name = name;
this.price = price;
this.taxPercent = tax;
@@ -37,6 +33,30 @@ public BigDecimal getTaxPercent() {
}
public BigDecimal getPriceWithTax() {
- return price.add(price.multiply(taxPercent));
+ return price.multiply(taxPercent).add(price);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+
+ Product product = (Product) object;
+
+ return Objects.equals(getName(), product.getName())
+ && getPrice().compareTo(product.getPrice()) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ getClass(),
+ getName(),
+ getPrice().stripTrailingZeros());
}
}
diff --git a/src/main/java/pl/edu/agh/mwo/invoice/product/package-info.java b/src/main/java/pl/edu/agh/mwo/invoice/product/package-info.java
new file mode 100644
index 000000000..b08eb4784
--- /dev/null
+++ b/src/main/java/pl/edu/agh/mwo/invoice/product/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Provides classes representing different types of products.
+ */
+package pl.edu.agh.mwo.invoice.product;
\ No newline at end of file
diff --git a/src/test/java/pl/edu/agh/mwo/invoice/InvoiceTest.java b/src/test/java/pl/edu/agh/mwo/invoice/InvoiceTest.java
index 7f4b6f795..f15ad2c48 100644
--- a/src/test/java/pl/edu/agh/mwo/invoice/InvoiceTest.java
+++ b/src/test/java/pl/edu/agh/mwo/invoice/InvoiceTest.java
@@ -12,10 +12,13 @@
import pl.edu.agh.mwo.invoice.product.OtherProduct;
import pl.edu.agh.mwo.invoice.product.Product;
import pl.edu.agh.mwo.invoice.product.TaxFreeProduct;
+import pl.edu.agh.mwo.invoice.product.BottleOfWine;
+import pl.edu.agh.mwo.invoice.product.FuelCanister;
public class InvoiceTest {
private Invoice invoice;
+
@Before
public void createEmptyInvoiceForTheTest() {
invoice = new Invoice();
@@ -23,17 +26,17 @@ public void createEmptyInvoiceForTheTest() {
@Test
public void testEmptyInvoiceHasEmptySubtotal() {
- Assert.assertThat(BigDecimal.ZERO, Matchers.comparesEqualTo(invoice.getSubtotal()));
+ Assert.assertThat(BigDecimal.ZERO, Matchers.comparesEqualTo(invoice.getNetTotal()));
}
@Test
public void testEmptyInvoiceHasEmptyTaxAmount() {
- Assert.assertThat(BigDecimal.ZERO, Matchers.comparesEqualTo(invoice.getTax()));
+ Assert.assertThat(BigDecimal.ZERO, Matchers.comparesEqualTo(invoice.getTaxTotal()));
}
@Test
public void testEmptyInvoiceHasEmptyTotal() {
- Assert.assertThat(BigDecimal.ZERO, Matchers.comparesEqualTo(invoice.getTotal()));
+ Assert.assertThat(BigDecimal.ZERO, Matchers.comparesEqualTo(invoice.getGrossTotal()));
}
@Test
@@ -42,21 +45,21 @@ public void testInvoiceSubtotalWithTwoDifferentProducts() {
Product apples = new TaxFreeProduct("Owoce", new BigDecimal("10"));
invoice.addProduct(onions);
invoice.addProduct(apples);
- Assert.assertThat(new BigDecimal("20"), Matchers.comparesEqualTo(invoice.getSubtotal()));
+ Assert.assertThat(new BigDecimal("20"), Matchers.comparesEqualTo(invoice.getNetTotal()));
}
@Test
public void testInvoiceSubtotalWithManySameProducts() {
Product onions = new TaxFreeProduct("Warzywa", BigDecimal.valueOf(10));
invoice.addProduct(onions, 100);
- Assert.assertThat(new BigDecimal("1000"), Matchers.comparesEqualTo(invoice.getSubtotal()));
+ Assert.assertThat(new BigDecimal("1000"), Matchers.comparesEqualTo(invoice.getNetTotal()));
}
@Test
public void testInvoiceHasTheSameSubtotalAndTotalIfTaxIsZero() {
Product taxFreeProduct = new TaxFreeProduct("Warzywa", new BigDecimal("199.99"));
invoice.addProduct(taxFreeProduct);
- Assert.assertThat(invoice.getTotal(), Matchers.comparesEqualTo(invoice.getSubtotal()));
+ Assert.assertThat(invoice.getNetTotal(), Matchers.comparesEqualTo(invoice.getGrossTotal()));
}
@Test
@@ -64,7 +67,7 @@ public void testInvoiceHasProperSubtotalForManyProducts() {
invoice.addProduct(new TaxFreeProduct("Owoce", new BigDecimal("200")));
invoice.addProduct(new DairyProduct("Maslanka", new BigDecimal("100")));
invoice.addProduct(new OtherProduct("Wino", new BigDecimal("10")));
- Assert.assertThat(new BigDecimal("310"), Matchers.comparesEqualTo(invoice.getSubtotal()));
+ Assert.assertThat(new BigDecimal("310"), Matchers.comparesEqualTo(invoice.getNetTotal()));
}
@Test
@@ -75,7 +78,7 @@ public void testInvoiceHasProperTaxValueForManyProduct() {
invoice.addProduct(new DairyProduct("Kefir", new BigDecimal("100")));
// tax: 2.30
invoice.addProduct(new OtherProduct("Piwko", new BigDecimal("10")));
- Assert.assertThat(new BigDecimal("10.30"), Matchers.comparesEqualTo(invoice.getTax()));
+ Assert.assertThat(new BigDecimal("10.30"), Matchers.comparesEqualTo(invoice.getTaxTotal()));
}
@Test
@@ -86,7 +89,7 @@ public void testInvoiceHasProperTotalValueForManyProduct() {
invoice.addProduct(new DairyProduct("Maslo", new BigDecimal("100")));
// price with tax: 12.30
invoice.addProduct(new OtherProduct("Chipsy", new BigDecimal("10")));
- Assert.assertThat(new BigDecimal("320.30"), Matchers.comparesEqualTo(invoice.getTotal()));
+ Assert.assertThat(new BigDecimal("320.30"), Matchers.comparesEqualTo(invoice.getGrossTotal()));
}
@Test
@@ -97,7 +100,7 @@ public void testInvoiceHasPropoerSubtotalWithQuantityMoreThanOne() {
invoice.addProduct(new DairyProduct("Kozi Serek", new BigDecimal("10")), 3);
// 1000x pinezka - price: 10
invoice.addProduct(new OtherProduct("Pinezka", new BigDecimal("0.01")), 1000);
- Assert.assertThat(new BigDecimal("50"), Matchers.comparesEqualTo(invoice.getSubtotal()));
+ Assert.assertThat(new BigDecimal("50"), Matchers.comparesEqualTo(invoice.getNetTotal()));
}
@Test
@@ -108,7 +111,7 @@ public void testInvoiceHasPropoerTotalWithQuantityMoreThanOne() {
invoice.addProduct(new DairyProduct("Chedar", new BigDecimal("10")), 3);
// 1000x pinezka - price with tax: 12.30
invoice.addProduct(new OtherProduct("Pinezka", new BigDecimal("0.01")), 1000);
- Assert.assertThat(new BigDecimal("54.70"), Matchers.comparesEqualTo(invoice.getTotal()));
+ Assert.assertThat(new BigDecimal("54.70"), Matchers.comparesEqualTo(invoice.getGrossTotal()));
}
@Test(expected = IllegalArgumentException.class)
@@ -125,4 +128,79 @@ public void testInvoiceWithNegativeQuantity() {
public void testAddingNullProduct() {
invoice.addProduct(null);
}
-}
+
+ @Test
+ public void testInvoiceNumbersAreAssignedAutomatically() {
+ Invoice firstInvoice = new Invoice();
+ Invoice secondInvoice = new Invoice();
+
+ Assert.assertEquals(
+ firstInvoice.getNumber() + 1,
+ secondInvoice.getNumber()
+ );
+ }
+
+ @Test
+ public void testInvoicePrintoutContainsProductsAndInvoiceNumber() {
+ invoice.addProduct(
+ new TaxFreeProduct("Kubek", new BigDecimal("5")), 2);
+ invoice.addProduct(
+ new DairyProduct("Ser", new BigDecimal("10")), 3);
+
+ String separator = System.lineSeparator();
+
+ String expected = "Numer faktury: "
+ + invoice.getNumber()
+ + separator
+ + "Kubek, 2 szt., 5"
+ + separator
+ + "Ser, 3 szt., 10"
+ + separator
+ + "Liczba pozycji: 2";
+
+ Assert.assertEquals(expected, invoice.getPrintout());
+ }
+
+ @Test
+ public void testAddingEquivalentProductsIncreasesQuantity() {
+ Product firstMug = new TaxFreeProduct(
+ "Kubek", new BigDecimal("5"));
+
+ Product secondMug = new TaxFreeProduct(
+ "Kubek", new BigDecimal("5.00"));
+
+ invoice.addProduct(firstMug, 2);
+ invoice.addProduct(secondMug, 3);
+
+ String separator = System.lineSeparator();
+
+ String expected = "Numer faktury: "
+ + invoice.getNumber()
+ + separator
+ + "Kubek, 5 szt., 5"
+ + separator
+ + "Liczba pozycji: 1";
+
+ Assert.assertEquals(expected, invoice.getPrintout());
+ }
+
+ @Test
+ public void testBottleOfWineIncludesVatAndExciseDuty() {
+ invoice.addProduct(
+ new BottleOfWine("Wino", new BigDecimal("10")));
+
+ Assert.assertThat(
+ new BigDecimal("7.86"),
+ Matchers.comparesEqualTo(invoice.getTaxTotal()));
+ }
+
+ @Test
+ public void testFuelCanisterIncludesOnlyExciseDuty() {
+ invoice.addProduct(
+ new FuelCanister("Paliwo", new BigDecimal("10")));
+
+ Assert.assertThat(
+ new BigDecimal("5.56"),
+ Matchers.comparesEqualTo(invoice.getTaxTotal()));
+ }
+ }