--- title: "Jam 07 - Exercise 5: System Integration" tags: - 2 ๐Ÿ“ in writing - 3 ๐Ÿงช in testing - 4 ๐Ÿฅณ done - inheritance - interfaces - polymorphism - uml - abstract-classes - junit --- <!-- markdownlint-disable line-length single-h1 no-inline-html --> <!-- markdownlint-configure-file { "ul-indent": { "indent": 4 }, "link-fragments": {"ignore_case": true} } --> {%hackmd dJZ5TulxSDKme-3fSY4Lbw %} # Exercise 5 - System Integration ## Overview - Exercise 5 You've worked incredibly hard implementing interfaces, exceptions, inheritance hierarchies, and state diagrams! ๐ŸŒŸ Now it's time to bring everything together. Rather than having you write all the integration code from scratch, we'll provide you with a well-structured implementation that ties all your components together. Your task is to understand how these pieces work together and why certain design choices were made. This approach mirrors real-world development, where you often need to: - Read and understand existing code - See how different components interact - Learn from established patterns and practices - Make informed modifications to complex systems As you review the code, think about: - How the Employee hierarchy controls access to Register operations - How the Searchable interface enables unified search across different types - How exceptions help maintain system integrity - How state management ensures proper operation sequencing Let's dive in and see how all your hard work comes together! ๐Ÿš€ Note: I'm about 92% certain this implementation *should* work regardless of how you implemented your code. If you get stuck and something doesn't work, post on Discord! ## Step 1: Add Employee Field to Register First, let's add the `currentUser` field to the Register class: ```java public class Register { // ... existing fields ... private Employee currentUser; // Add this field // ... existing methods ... } ``` ## Step 2: Add Login/Logout Methods Add these methods to the Register class: ```java public class Register { // ... existing code ... public boolean login(Employee employee) { if (currentUser != null) { return false; // Already logged in } currentUser = employee; return true; } public boolean logout() { if (currentUser == null) { return false; // Already logged out } currentUser = null; return true; } public Employee getCurrentUser() { return currentUser; } } ``` ## Step 3: Add Permission Check Method Add this method to check if the current user has permission for an operation: ```java public class Register { // ... existing code ... private boolean shouldBlockOperation(boolean requiresAdmin) { if (currentUser == null) { return true; // No user logged in means operation should be blocked } if (requiresAdmin) { return !currentUser.hasAdminPrivileges(); // Block if user doesn't have admin privileges } return !currentUser.canAccessRegister(); // Block if user can't access register } } ``` ## Step 4: Update Transaction Methods Now let's update the transaction methods to require login: ```java public class Register { // ... existing code ... public boolean startTransaction() { if (shouldBlockOperation(false)) { return false; } // ... existing startTransaction code ... } public boolean addProductToTransaction(String sku) { if (shouldBlockOperation(false)) { return false; } // ... existing addProductToTransaction code ... } public Map<Money, Integer> processPayment(Map<Money, Integer> payment) { if (shouldBlockOperation(false)) { return null; } // ... existing processPayment code ... } } ``` ## Step 5: Create Integration Test Create a new test file `RegisterIntegrationTest.java` in the `jam07` test folder: ```java package jam07; import static org.junit.jupiter.api.Assertions.*; import jam05.Product; import jam05.ProductCatalog; import jam06.Register; import java.time.LocalDate; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class RegisterIntegrationTest { private static int registerCounter = 0; private Register register; private Cashier cashier; private Manager manager; private Product testProduct; @BeforeEach void setUp() { // Set up catalog and register ProductCatalog catalog = new ProductCatalog(); try { testProduct = new Product("Test Product", "TEST123", 9.99); catalog.addProduct(testProduct); } catch (jam07.InvalidPriceException e) { System.err.println("Error creating product: " + e.getMessage()); System.exit(1); } String registerName = String.format("TEST-%03d", ++registerCounter); register = Register.createRegister(registerName, catalog); cashier = new Cashier("C001", "Test Cashier", LocalDate.now()); manager = new Manager("M001", "Test Manager", LocalDate.now()); } @Test void shouldRequireLoginForOperations() { // Test operations without login assertFalse(register.startTransaction()); assertFalse(register.addProductToTransaction(testProduct.getSku())); // Login as cashier assertTrue(register.login(cashier)); // Test operations with login assertTrue(register.startTransaction()); assertTrue(register.addProductToTransaction(testProduct.getSku())); } @Test void shouldAllowManagerAdminOperations() { // Login as manager assertTrue(register.login(manager)); // Test admin operations assertTrue(manager.hasAdminPrivileges()); } @Test void shouldManageUserLoginAndLogout() { // Initially no user should be logged in assertNull(register.getCurrentUser()); // Login as cashier assertTrue(register.login(cashier)); assertEquals(cashier, register.getCurrentUser()); // Try to log-in again (should fail) assertFalse(register.login(manager)); assertEquals(cashier, register.getCurrentUser()); // Should still be a cashier // Logout assertTrue(register.logout()); assertNull(register.getCurrentUser()); // Try to log-out again (should fail) assertFalse(register.logout()); assertNull(register.getCurrentUser()); } @Test void shouldEnforceAdminPrivileges() { // Log-in as cashier assertTrue(register.login(cashier)); // Cashier should be able to perform regular operations assertTrue(register.startTransaction()); assertTrue(register.addProductToTransaction(testProduct.getSku())); // Cashier should be able to perform basic searches assertTrue(register.matches("TEST-001")); // Can search register name assertTrue(register.matches("0")); // Can search drawer balance // Cashier should not be able to perform admin operations assertNull(register.getCompletedTransactions()); // Logout and login as manager assertTrue(register.logout()); assertTrue(register.login(manager)); // Manager should be able to perform both regular and admin operations assertTrue(register.voidTransaction()); assertTrue(register.startTransaction()); assertTrue(register.addProductToTransaction(testProduct.getSku())); // Manager should have full search capabilities assertTrue(register.matches("TEST-001")); // Can search register name assertTrue(register.matches("0")); // Can search drawer balance assertFalse(register.searchTransactions("IN_PROGRESS") .isEmpty()); // Can search transactions // Manager should be able to perform admin operations assertNotNull(register.getCompletedTransactions()); } } ``` ## Step 6: Run and Verify Tests 1. Run the tests to verify your implementation: ```bash # Right click on the test folder in IntelliJ # Click "Run Tests in 'csci205_jams'" ``` 2. Fix any failing tests by: - Checking error messages - Verifying method implementations - Ensuring proper permission checks - Testing edge cases ## Save Your Work - Exercise 5 **Run all tests to verify your implementation**: ```bash # Right click on the test folder in IntelliJ # Click "Run Tests in 'csci205_jams'" # Ensure all tests pass ``` **Stage your changes**: ```bash git add src/main/java/jam06/Register.java src/test/java/jam07/EmployeeTest.java src/test/java/jam07/ProductCatalogTest.java src/test/java/jam07/ProductTest.java src/test/java/jam07/RegisterIntegrationTest.java src/test/java/jam07/RegisterTest.java src/test/java/jam07/TransactionTest.java ``` **Verify what files are uncommitted**: ```bash git status ``` **Commit your work**: ```bash git commit -m "jam07: Add employee authentication to Register" ``` :::success ๐Ÿ”‘ **Key Takeaways** - Components must work together seamlessly - Integration testing is crucial - Error handling must be comprehensive - State management is critical - Documentation ensures maintainability - Testing verifies system behavior ::: Remember: Every great developer started exactly where you did. Keep building, keep learning, and most importantly - be proud of how far you've come! ๐ŸŒŸ