Copy cat > /tmp/Lab09.java << 'JAVAEOF'
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class Lab09 {
record Product(int id, String name, double price, int stock) {
boolean inStock() { return stock > 0; }
double value() { return price * stock; }
Product withPrice(double p) { return new Product(id, name, p, stock); }
Product withStock(int s) { return new Product(id, name, price, s); }
}
static class ProductService {
private final Map<Integer, Product> catalog = new LinkedHashMap<>();
void add(Product p) { catalog.put(p.id(), p); }
Optional<Product> findById(int id) { return Optional.ofNullable(catalog.get(id)); }
List<Product> inStock() { return catalog.values().stream().filter(Product::inStock).toList(); }
double totalValue() { return catalog.values().stream().mapToDouble(Product::value).sum(); }
Optional<Product> cheapest() { return catalog.values().stream().min(Comparator.comparingDouble(Product::price)); }
int size() { return catalog.size(); }
}
static int passed = 0, failed = 0;
static void test(String name, Runnable fn) {
try { fn.run(); System.out.println(" PASS: " + name); passed++; }
catch (AssertionError e) { System.out.println(" FAIL: " + name + " -> " + e.getMessage()); failed++; }
catch (Exception e) { System.out.println(" ERROR: " + name + " -> " + e.getMessage()); failed++; }
}
static void assertEquals(Object expected, Object actual, String msg) {
if (!Objects.equals(expected, actual))
throw new AssertionError(msg + ": expected=<" + expected + "> actual=<" + actual + ">");
}
static void assertTrue(boolean cond, String msg) { if (!cond) throw new AssertionError(msg); }
static void assertFalse(boolean cond, String msg) { if (cond) throw new AssertionError(msg); }
static void assertApprox(double expected, double actual, double tol, String msg) {
if (Math.abs(expected - actual) > tol)
throw new AssertionError(msg + ": expected~" + expected + " actual=" + actual);
}
static <E extends Exception> void assertThrows(Class<E> type, Runnable fn, String msg) {
try { fn.run(); throw new AssertionError(msg + ": expected " + type.getSimpleName() + " not thrown"); }
catch (Exception e) { if (!type.isInstance(e)) throw new AssertionError(msg + ": wrong exception: " + e.getClass().getSimpleName()); }
}
static ProductService makeService() {
var svc = new ProductService();
svc.add(new Product(1, "Surface Pro", 864.0, 15));
svc.add(new Product(2, "Surface Pen", 49.99, 80));
svc.add(new Product(3, "Office 365", 99.99, 999));
svc.add(new Product(4, "USB-C Hub", 29.99, 0));
return svc;
}
public static void main(String[] args) {
System.out.println("=== ProductService Test Suite ===\n");
System.out.println("-- findById --");
test("findById existing", () -> {
var svc = makeService();
var p = svc.findById(1);
assertTrue(p.isPresent(), "should be present");
assertEquals("Surface Pro", p.get().name(), "name");
});
test("findById missing returns empty", () -> {
assertFalse(makeService().findById(99).isPresent(), "should be absent");
});
System.out.println("\n-- inStock --");
test("inStock returns only stocked products", () -> {
var results = makeService().inStock();
assertEquals(3, results.size(), "inStock count");
assertTrue(results.stream().allMatch(Product::inStock), "all in stock");
});
test("USB-C Hub is OOS", () -> {
assertFalse(makeService().findById(4).orElseThrow().inStock(), "USB-C Hub OOS");
});
System.out.println("\n-- analytics --");
test("totalValue correct", () -> {
assertApprox(116849.21, makeService().totalValue(), 0.01, "totalValue");
});
test("cheapest is USB-C Hub", () -> {
assertEquals("USB-C Hub", makeService().cheapest().orElseThrow().name(), "cheapest");
});
System.out.println("\n-- immutability --");
test("withPrice returns new record", () -> {
var p = new Product(1, "Surface Pro", 864.0, 15);
var p2 = p.withPrice(799.0);
assertEquals(864.0, p.price(), "original unchanged");
assertEquals(799.0, p2.price(), "new price");
});
test("records are value-equal", () -> {
var p1 = new Product(1, "Surface Pro", 864.0, 15);
var p2 = new Product(1, "Surface Pro", 864.0, 15);
assertEquals(p1, p2, "records equal");
});
System.out.println("\n-- edge cases --");
test("empty service totalValue=0", () -> {
assertApprox(0.0, new ProductService().totalValue(), 0.001, "empty total");
});
test("cheapest on empty returns empty", () -> {
assertFalse(new ProductService().cheapest().isPresent(), "empty cheapest");
});
test("duplicate id overwrites", () -> {
var svc = new ProductService();
svc.add(new Product(1, "Old", 100.0, 10));
svc.add(new Product(1, "New", 200.0, 20));
assertEquals(1, svc.size(), "still 1 product");
assertEquals("New", svc.findById(1).get().name(), "overwritten");
});
System.out.println("\n-- parametrized data-driven --");
record TestCase(int id, String expectedName, double expectedPrice) {}
var cases = List.of(
new TestCase(1, "Surface Pro", 864.0),
new TestCase(2, "Surface Pen", 49.99),
new TestCase(3, "Office 365", 99.99)
);
var svc = makeService();
for (var tc : cases) {
test("product[" + tc.id() + "] name=" + tc.expectedName(), () -> {
var p = svc.findById(tc.id()).orElseThrow();
assertEquals(tc.expectedName(), p.name(), "name");
assertApprox(tc.expectedPrice(), p.price(), 0.001, "price");
});
}
System.out.println("\n=== Results ===");
System.out.printf(" %d passed, %d failed (%d total)%n", passed, failed, passed+failed);
if (failed > 0) System.exit(1);
}
}
JAVAEOF
docker run --rm -v /tmp/Lab09.java:/tmp/Lab09.java zchencow/innozverse-java:latest sh -c "javac /tmp/Lab09.java -d /tmp && java -cp /tmp Lab09"