Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,37 @@ Keuntungan menerapkan prinsip SOLID
Kerugian tidak menerapkan prinsip SOLID
- Kode hanya dipahami oleh orang yang menulis kode, orang lain yang membaca kode lebih banyak menghabiskan waktunya dalam memahami kode lama dibanding membuat kode baru
- Kode sulit dikelola, sulit menambah fitur, dan tidak fleksibel
- Apabila menemukan error atau bug akan sulit melacak kode penyebabnya
- Apabila menemukan error atau bug akan sulit melacak kode penyebabnya

## Module 4

Menurut saya alur TDD (Test-Driven Development) sudah membantu saya selama melakukan pemograman dalam aplikasi Springboot ini, sebab saya sudah menetapkan ekspektasi output program dari awal, sehingga saat melakukan pemrograman menjadi lebih terarah.


F.I.R.S.T. principle or not. If not, explain things that you need to do the next time you create more tests.

- Fast : sudah terpenuhi karena saya memisahkan tests menjadi unit tests dan functional tests, serta menggunakan stubs contohnya InjectMocks OrderServiceImpl dan Mock orderRepository, sehingga test dapat berjalan dengan cepat
- Isolated/Independent : sudah terpenuhi karena saya sudah set up objek dummy atau mock sebelum test case, contohnya pada `OrderTest.java` terdapat method BeforeEach
```java
@BeforeEach
void setUp() {
this.products = new ArrayList<>();

Product product1 = new Product();
product1.setProductId("eb558e9f-1c39-460e-8860-71af6af63bd6");
product1.setProductName("Sampo Cap Bambang");
product1.setProductQuantity(2);

Product product2 = new Product();
product2.setProductId("a2c62328-4a37-4664-83c7-f32db8620155");
product2.setProductName("Sabun Cap Usep");
product2.setProductQuantity(1);

this.products.add(product1);
this.products.add(product2);
}
```

- Repeatable: sudah terpenuhi karena test yang saya buat sudah terisolasi dan dapat berjalan berkali-kali dengan hasil yang konsisten.
- Self-Validating: sudah terpenuhi karena test saya sudah strict serta menggunakan assertions daripada print secara manual. Namun masih beberapa kekurangan yang dapat diimprove seperti kurangnya pesan dalam tiap assertion dan terlalu banyak assertion dalam satu test method.
- Thorough/Timely: sudah terpenuhi karena test yang saya buat sudah mencover semua happy & unhappy path yang mencankup semua kemungkinan error.
26 changes: 26 additions & 0 deletions src/main/java/id/ac/ui/cs/advprog/eshop/enums/OrderStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package id.ac.ui.cs.advprog.eshop.enums;


import lombok.Getter;

@Getter
public enum OrderStatus {
WAITING_PAYMENT("WAITING_PAYMENT"),
FAILED("FAILED"),
SUCCESS("SUCCESS"),
CANCELLED("CANCELLED");

private final String value;
private OrderStatus (String value) {

Check warning

Code scanning / PMD

Unnecessary modifier 'public' on method 'getAllPayments': the method is declared in an interface type

Unnecessary modifier 'private' on constructor 'OrderStatus(String)': enum constructors are implicitly private
this.value = value;
}

public static boolean contains(String param) {
for (OrderStatus orderStatus : OrderStatus.values()) {

Check warning

Code scanning / PMD

Unnecessary qualifier 'PaymentStatus': 'values' is already in scope

Unnecessary qualifier 'OrderStatus': 'values' is already in scope
if (orderStatus.name().equals(param)) {
return true;
}
}
return false;
}
}
23 changes: 23 additions & 0 deletions src/main/java/id/ac/ui/cs/advprog/eshop/enums/PaymentStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package id.ac.ui.cs.advprog.eshop.enums;

import lombok.Getter;

@Getter
public enum PaymentStatus {
SUCCESS("SUCCESS"),
REJECTED("REJECTED");

private final String value;
private PaymentStatus (String value) {

Check warning

Code scanning / PMD

Unnecessary modifier 'public' on method 'getAllPayments': the method is declared in an interface type

Unnecessary modifier 'private' on constructor 'PaymentStatus(String)': enum constructors are implicitly private
this.value = value;
}

public static boolean contains(String param) {
for (PaymentStatus paymentStatus : PaymentStatus.values()) {

Check warning

Code scanning / PMD

Unnecessary qualifier 'PaymentStatus': 'values' is already in scope

Unnecessary qualifier 'PaymentStatus': 'values' is already in scope
if (paymentStatus.name().equals(param)) {
return true;
}
}
return false;
}
}
45 changes: 45 additions & 0 deletions src/main/java/id/ac/ui/cs/advprog/eshop/model/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package id.ac.ui.cs.advprog.eshop.model;


import id.ac.ui.cs.advprog.eshop.enums.OrderStatus;
import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Builder
@Getter
public class Order {

String id;
List<Product> products;
Long orderTime;
String author;
String status;

public Order(String id, List<Product> products, Long orderTime, String author) {
this.id = id;
this.orderTime = orderTime;
this.author = author;
this.status = OrderStatus.WAITING_PAYMENT.getValue();

if (products.isEmpty()){
throw new IllegalArgumentException();
} else{
this.products = products;
}
}

public Order(String id, List<Product> products, Long orderTime, String author, String status) {
this(id, products,orderTime, author);
this.setStatus(status);
}

public void setStatus(String status){
if (OrderStatus.contains(status)){
this.status = status;
} else{
throw new IllegalArgumentException();
}
}
}
58 changes: 58 additions & 0 deletions src/main/java/id/ac/ui/cs/advprog/eshop/model/Payment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package id.ac.ui.cs.advprog.eshop.model;

import id.ac.ui.cs.advprog.eshop.enums.OrderStatus;

Check warning

Code scanning / PMD

Unused import 'id.ac.ui.cs.advprog.eshop.enums.PaymentStatus'

Unused import 'id.ac.ui.cs.advprog.eshop.enums.OrderStatus'
import id.ac.ui.cs.advprog.eshop.enums.PaymentStatus;
import lombok.Builder;

Check warning

Code scanning / PMD

Unused import 'id.ac.ui.cs.advprog.eshop.enums.PaymentStatus'

Unused import 'lombok.Builder'
import lombok.Getter;


import java.util.Map;


@Getter
public abstract class Payment {

String id;
Order order;
Map<String, String> paymentData;

String status;



public Payment(String id, Order order, Map<String, String> paymentData) {
this.id = id;
this.order = order;
this.paymentData = paymentData;


if (paymentDataIsValid()){
setStatus("SUCCESS");
} else{
setStatus("REJECTED");
}
}
public Payment(String id, Order order, Map<String, String> paymentData, String status) {
this.id = id;
this.order = order;
this.paymentData = paymentData;
setStatus(status);
}
public void setStatus(String status){
if (PaymentStatus.contains(status)){
this.status = status;

if (status.equals("SUCCESS")){

Check warning

Code scanning / PMD

Position literals first in String comparisons

Position literals first in String comparisons
order.setStatus("SUCCESS");
} else if (status.equals("REJECTED")){

Check warning

Code scanning / PMD

Position literals first in String comparisons

Position literals first in String comparisons
order.setStatus("FAILED");
}

} else{
throw new IllegalArgumentException();
}

}

abstract boolean paymentDataIsValid();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package id.ac.ui.cs.advprog.eshop.model;


import lombok.Builder;

Check warning

Code scanning / PMD

Unused import 'id.ac.ui.cs.advprog.eshop.enums.PaymentStatus'

Unused import 'lombok.Builder'

import java.util.Map;

public class PaymentCashOnDelivery extends Payment{
public PaymentCashOnDelivery(String id, Order order, Map<String, String> paymentData) {
super(id, order, paymentData);
}

@Override
boolean paymentDataIsValid() {
String address = paymentData.get("address");
String deliveryFee = paymentData.get("deliveryFee");

return address != null && !address.isEmpty() && deliveryFee != null && !deliveryFee.isEmpty();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package id.ac.ui.cs.advprog.eshop.model;

import lombok.Builder;

Check warning

Code scanning / PMD

Unused import 'id.ac.ui.cs.advprog.eshop.enums.PaymentStatus'

Unused import 'lombok.Builder'

import java.util.Map;

public class PaymentVoucherCode extends Payment{
public PaymentVoucherCode(String id, Order order, Map<String, String> paymentData) {
super(id, order, paymentData);
}

@Override
boolean paymentDataIsValid() {
String voucherCode = paymentData.get("voucherCode");
if (voucherCode == null || voucherCode.length() != 16 || !voucherCode.startsWith("ESHOP")) {
return false;
}

int numCharCount = 0;
for (int i = 0; i < voucherCode.length(); i++){
if (Character.isDigit(voucherCode.charAt(i))){
numCharCount++;
}
}

if (numCharCount != 8){
return false;
}
Comment on lines +26 to +28

Check warning

Code scanning / PMD

This if statement can be replaced by `return !{condition};`

This if statement can be replaced by `return !{condition};`


return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package id.ac.ui.cs.advprog.eshop.repository;

import org.springframework.stereotype.Repository;
import id.ac.ui.cs.advprog.eshop.model.Order;

import java.util.ArrayList;
import java.util.List;

@Repository
public class OrderRepository {
private List<Order> orderData = new ArrayList<>();
public Order save(Order order) {
int i = 0;
for (Order savedOrder : orderData){
if (savedOrder.getId().equals(order.getId())){
orderData.remove(i);
orderData.add(i, order);
return order;
}
i += 1;
}

orderData.add(order);
return order;
}
public Order findById(String id){
for (Order savedOrder : orderData){
if (savedOrder.getId().equals(id)){
return savedOrder;
}
}
return null;
}
public List<Order> findAllByAuthor(String author){
List<Order> result = new ArrayList<>();
for (Order savedOrder : orderData){
if (savedOrder.getAuthor().equals(author)){
result.add(savedOrder);
}
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package id.ac.ui.cs.advprog.eshop.repository;

import id.ac.ui.cs.advprog.eshop.model.Payment;

import java.util.ArrayList;
import java.util.List;

public class PaymentRepository {
private List<Payment> paymentData = new ArrayList<>();

public Payment save(Payment payment) {
int i = 0;
for (Payment savedPayment : paymentData){
if (savedPayment.getId().equals(payment.getId())){
paymentData.remove(i);
paymentData.add(i, payment);
return payment;
}
i += 1;
}

paymentData.add(payment);

return payment;
}
public Payment findById(String id){
for (Payment savedPayment : paymentData){
if (savedPayment.getId().equals(id)){
return savedPayment;
}
}
return null;
}
public List<Payment> getAllPayment(){
return paymentData;
}
}
12 changes: 12 additions & 0 deletions src/main/java/id/ac/ui/cs/advprog/eshop/service/OrderService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package id.ac.ui.cs.advprog.eshop.service;

import id.ac.ui.cs.advprog.eshop.model.Order;

import java.util.List;

public interface OrderService {
public Order createOrder (Order order);

Check warning

Code scanning / PMD

Unnecessary modifier 'public' on method 'getAllPayments': the method is declared in an interface type

Unnecessary modifier 'public' on method 'createOrder': the method is declared in an interface type
public Order updateStatus(String orderId, String status);

Check warning

Code scanning / PMD

Unnecessary modifier 'public' on method 'getAllPayments': the method is declared in an interface type

Unnecessary modifier 'public' on method 'updateStatus': the method is declared in an interface type
public Order findById(String orderId);

Check warning

Code scanning / PMD

Unnecessary modifier 'public' on method 'getAllPayments': the method is declared in an interface type

Unnecessary modifier 'public' on method 'findById': the method is declared in an interface type
public List<Order> findAllByAuthor(String author);

Check warning

Code scanning / PMD

Unnecessary modifier 'public' on method 'getAllPayments': the method is declared in an interface type

Unnecessary modifier 'public' on method 'findAllByAuthor': the method is declared in an interface type
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package id.ac.ui.cs.advprog.eshop.service;

import id.ac.ui.cs.advprog.eshop.model.Order;
import id.ac.ui.cs.advprog.eshop.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.NoSuchElementException;

@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderRepository orderRepository;
@Override
public Order createOrder(Order order){
if (orderRepository.findById(order.getId()) == null){
orderRepository.save(order);
return order;
}
return null;
}
@Override
public Order updateStatus(String orderId, String status){
Order order = orderRepository.findById(orderId);
if (order != null){
Order newOrder = new Order(order.getId(), order.getProducts(),
order.getOrderTime(), order.getAuthor(), status);
orderRepository.save(newOrder);
return newOrder;
} else{
throw new NoSuchElementException();
}
}
@Override
public List<Order> findAllByAuthor(String author){
return orderRepository.findAllByAuthor(author);
}
@Override
public Order findById(String orderId){
return orderRepository.findById(orderId);
}
}
Loading