diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2623864 --- /dev/null +++ b/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + com.github.javadev + java_stream_api + 1.0 + java_stream_api + + + 1.8 + 1.8 + UTF-8 + 5.13.0 + + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + false + + + + + + diff --git a/src/main/java/java-stream-api/App.java b/src/main/java/java_stream_api/App.java similarity index 78% rename from src/main/java/java-stream-api/App.java rename to src/main/java/java_stream_api/App.java index 1b00b63..03d9d8e 100644 --- a/src/main/java/java-stream-api/App.java +++ b/src/main/java/java_stream_api/App.java @@ -1,262 +1,297 @@ package java_stream_api; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + public class App { // 1. Find the number of elements in a list of strings. public static long findNumberOfElements(List strList) { return strList.stream().count(); } - + // 2. Convert all strings in a list to uppercase. public static List convertStringsToUppercase(List strList) { return strList.stream().map(String::toUpperCase).collect(Collectors.toList()); } - + // 3. Filter a list of strings, keeping only those that start with the letter 'A'. public static List filterStringsStartingWithA(List strList) { return strList.stream().filter(el -> el.startsWith("A")).collect(Collectors.toList()); } - + // 4. Obtain unique integers from a list. public static List uniqueIntegers(List intsList) { return intsList.stream().distinct().collect(Collectors.toList()); } - + // 5. Calculate the sum of all numbers in a list of integers. public static int sumOfIntegers(List intsList) { return intsList.stream().mapToInt(Integer::intValue).sum(); } - + // 6. Find the minimum number in a list of integers. public static int minOfIntegers(List intsList) { return intsList.stream().mapToInt(Integer::intValue).min().orElse(Integer.MIN_VALUE); } - + // 7. Find the maximum number in a list of integers. public static int maxOfIntegers(List intsList) { return intsList.stream().mapToInt(Integer::intValue).max().orElse(Integer.MAX_VALUE); } - + // 8. Concatenate all strings from a list into one string, separated by commas. public static String concatenateStringsWithComma(List strList) { return strList.stream().collect(Collectors.joining(", ")); } - + // 9. Get the first element of a list of integers or 0 if the list is empty. public static int getFirstIntegerOrZero(List intsList) { return intsList.stream().mapToInt(Integer::intValue).findFirst().orElse(0); } - + // 10. Get the last element of a list of strings or "" if empty. public static String getLastString(List strList) { return strList.stream().reduce((first, second) -> second).orElse(""); } - + // 11. Convert a list of integers into a list of their squares. public static List listOfSquares(List intsList) { return intsList.stream().map(i -> i * i).collect(Collectors.toList()); } - + // 12. Filter a list of integers, keeping only even numbers. public static List filterEvenNumbers(List intsList) { return intsList.stream().filter(n -> n % 2 == 0).collect(Collectors.toList()); } - + // 13. Find people older than 18 years and return a list of their names. - public static List namesOfUsersOlderThan18(List users) { - return users.stream().filter(u -> u.getAge() > 18).map(User::getName).collect(Collectors.toList()); + public static List namesOfUsersOlderThan18(List users) { + return users.stream() + .filter(u -> u.getAge() > 18) + .map(java_stream_api.User::getName) + .collect(Collectors.toList()); } - + // 14. Sort a list of strings by their length. public static List sortStringsByLength(List strList) { - return strList.stream().sorted(Comparator.comparing(String::length)).collect(Collectors.toList()); + return strList.stream() + .sorted(Comparator.comparing(String::length)) + .collect(Collectors.toList()); } - + // 15. Check if a list of strings contains at least one string that includes the word "Java." public static boolean containsStringWithJava(List strList) { return strList.stream().anyMatch(str -> str.contains("Java")); } - + // 16. Merge two lists of strings into one. public static List mergeTwoStringLists(List list1, List list2) { return Stream.concat(list1.stream(), list2.stream()).collect(Collectors.toList()); } - + // 17. Get the average value of all numbers in a list of integers. public static double averageOfIntegers(List intsList) { return intsList.stream().mapToInt(Integer::intValue).average().orElse(0.0); } - + // 18. Discard the first three elements in a list of integers. public static List discardFirstThreeIntegers(List intsList) { return intsList.stream().skip(3).collect(Collectors.toList()); } - + // 19. Keep only the first three elements of a list of integers. public static List keepFirstThreeIntegers(List intsList) { return intsList.stream().limit(3).collect(Collectors.toList()); } - + // 20. Convert each string into a list of integers representing the character codes. public static List stringToAsciiCodes(List strList) { return strList.stream().flatMapToInt(String::chars).boxed().collect(Collectors.toList()); } - + // 21. Count the number of strings longer than 5 characters. public static long countStringsLongerThan5(List strList) { return strList.stream().filter(s -> s.length() > 5).count(); } - + // 22. Create a map from a list of strings where key - string, value - its length. public static Map stringsToLengthMap(List strList) { return strList.stream().collect(Collectors.toMap(Function.identity(), String::length)); } - + // 23. Sort a list of users by their age. - public static List sortUsersByAge(List users) { - return users.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList()); + public static List sortUsersByAge(List users) { + return users.stream() + .sorted(Comparator.comparing(java_stream_api.User::getAge)) + .collect(Collectors.toList()); } - + // 24. Find the user with the maximum age. - public static Optional userWithMaxAge(List users) { - return users.stream().max(Comparator.comparing(User::getAge)); + public static Optional userWithMaxAge(List users) { + return users.stream().max(Comparator.comparing(java_stream_api.User::getAge)); } - + // 25. Check if all strings in a list are longer than 3 characters. public static boolean areAllStringsLongerThan3(List strList) { return strList.stream().allMatch(s -> s.length() > 3); } - + // 26. Select all every 3rd element from a list of strings (1-based). public static List selectEvery3rd(List strList) { AtomicInteger counter = new AtomicInteger(); - return strList.stream().filter(x -> counter.incrementAndGet() % 3 == 0).collect(Collectors.toList()); + return strList.stream() + .filter(x -> counter.incrementAndGet() % 3 == 0) + .collect(Collectors.toList()); } - + // 27. Calculate the total number of hobbies all users have. - public static int totalHobbiesCount(List users) { + public static int totalHobbiesCount(List users) { return users.stream().mapToInt(u -> u.getHobbies().size()).sum(); } - + // 28. Find a list of strings that appear more than once in a list. public static List duplicateStrings(List strList) { return strList.stream() - .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) - .entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey) - .collect(Collectors.toList()); + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) + .entrySet() + .stream() + .filter(e -> e.getValue() > 1) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); } - + // 29. Convert all users' birthdates to string "AGE MM YYYY". - public static List convertBirthdatesToString(List users) { + public static List convertBirthdatesToString( + List users) { users.forEach(user -> user.setBirthdate(user.getAge() + " MM YYYY")); return users; } - - // 30. Filter a list of Person objects, keeping only those who live in "City X". - public static List filterPersonsByCity(List persons, String city) { - return persons.stream().filter(p -> "City X".equals(p.getCity())).collect(Collectors.toList()); + + // 30. Filter a list of Person objects, keeping only those who live in "City X". + public static List filterPersonsByCity( + List persons, String city) { + return persons.stream() + .filter(p -> "City X".equals(p.getCity())) + .collect(Collectors.toList()); } - + // 31. Reverse the order of elements in a list. public static List reverseList(List list) { return IntStream.range(0, list.size()) .mapToObj(i -> list.get(list.size() - 1 - i)) .collect(Collectors.toList()); } - + // 32. Find the percentage of elements with the value "null" in a list. public static long percentageOfNulls(List list) { long nullCount = list.stream().filter(Objects::isNull).count(); return list.size() == 0 ? 0 : (nullCount * 100) / list.size(); } - + // 33. Shuffle the elements of a list randomly. public static void shuffleList(List list) { Collections.shuffle(list); } - + // 34. Group numbers by their remainder when divided by 3. public static Map> groupByRemainder3(List intsList) { return intsList.stream().collect(Collectors.groupingBy(n -> n % 3)); } - + // 35. Convert a list of integers into a list of booleans: true for even, false for odd. public static List evenIntegersAsBooleans(List intsList) { return intsList.stream().map(n -> n % 2 == 0).collect(Collectors.toList()); } - + // 36. Filter a list, keeping only unique elements, and return the result in reverse order. public static List uniqueElementsReversed(List list) { List unique = list.stream().distinct().collect(Collectors.toList()); Collections.reverse(unique); return unique; } - + // 37. Create a list of 100 random numbers and find the top 5 largest. public static List top5Of100Random() { Random rnd = new Random(); - return rnd.ints(100, 0, 1000).boxed() - .sorted(Comparator.reverseOrder()).limit(5) - .collect(Collectors.toList()); + return rnd.ints(100, 0, 1000) + .boxed() + .sorted(Comparator.reverseOrder()) + .limit(5) + .collect(Collectors.toList()); } - + // 38. Split a list of strings into groups by their length. public static Map> groupStringsByLength(List strList) { return strList.stream().collect(Collectors.groupingBy(String::length)); } - + // 39. Find the element in a list that has the largest length. public static String longestString(List strList) { return strList.stream().max(Comparator.comparing(String::length)).orElse(""); } - + // 40. Remove from the list all users whose name starts with "J." public static List removeUsersWithJ(List names) { return names.stream().filter(n -> !n.startsWith("J")).collect(Collectors.toList()); } - + // 41. Convert a list of integers into a map: number -> square. public static Map integersToSquareMap(List intsList) { return intsList.stream().collect(Collectors.toMap(n -> n, n -> n * n, (a, b) -> b)); } - + // 42. Find the total number of all words in a list of sentences. public static long totalWordsInSentences(List sentences) { return sentences.stream().flatMap(s -> Arrays.stream(s.split("\\s+"))).count(); } - + // 43. Create a list of strings "yes" or "no," based on whether a number is even. public static List yesNoIfEven(List intsList) { return intsList.stream().map(n -> n % 2 == 0 ? "yes" : "no").collect(Collectors.toList()); } - + // 44. Calculate the range in a list of numbers. public static int rangeOfNumbers(List intsList) { int min = intsList.stream().mapToInt(i -> i).min().orElse(0); int max = intsList.stream().mapToInt(i -> i).max().orElse(0); return max - min; } - + // 45. List of lengths of strings, sorted in descending order. public static List lengthsDescending(List strList) { - return strList.stream().map(String::length) - .sorted(Comparator.reverseOrder()).collect(Collectors.toList()); + return strList.stream() + .map(String::length) + .sorted(Comparator.reverseOrder()) + .collect(Collectors.toList()); } - + // 46. Find the sum of all string lengths in a list of strings. public static int sumStringLengths(List strList) { return strList.stream().mapToInt(String::length).sum(); } - + // 47. Count the number of elements equal to null in a list. public static long countNullElements(List list) { return list.stream().filter(Objects::isNull).count(); } - + // 48. Group users by their year of birth. - public static Map> groupUsersByBirthYear(List users) { - return users.stream().collect(Collectors.groupingBy(User::getBirthYear)); + public static Map> groupUsersByBirthYear( + List users) { + return users.stream().collect(Collectors.groupingBy(java_stream_api.User::getBirthYear)); } - + // 49. Find all unique characters in a list of strings and form them into a sorted list. public static List uniqueSortedCharacters(List strList) { return strList.stream() @@ -266,10 +301,11 @@ public static List uniqueSortedCharacters(List strList) { .sorted() .collect(Collectors.toList()); } - + // 50. Returns a list of user names, sorted by the length of these names. - public static List userNamesSortedByLength(List users) { - return users.stream().map(User::getName) + public static List userNamesSortedByLength(List users) { + return users.stream() + .map(java_stream_api.User::getName) .sorted(Comparator.comparingInt(String::length)) .collect(Collectors.toList()); } diff --git a/src/main/java/java_stream_api/Person.java b/src/main/java/java_stream_api/Person.java new file mode 100644 index 0000000..625714f --- /dev/null +++ b/src/main/java/java_stream_api/Person.java @@ -0,0 +1,32 @@ +package java_stream_api; + +import java.util.Objects; + +public class Person { + private final String name, city; + + public Person(String name, String city) { + this.name = name; + this.city = city; + } + + public String getName() { + return name; + } + + public String getCity() { + return city; + } + + @Override + public boolean equals(Object o) { + return (o instanceof Person) + && Objects.equals(((Person) o).name, name) + && Objects.equals(((Person) o).city, city); + } + + @Override + public int hashCode() { + return Objects.hash(name, city); + } +} diff --git a/src/main/java/java_stream_api/User.java b/src/main/java/java_stream_api/User.java new file mode 100644 index 0000000..adc2009 --- /dev/null +++ b/src/main/java/java_stream_api/User.java @@ -0,0 +1,53 @@ +package java_stream_api; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class User { + private String name; + private int age; + private String birthdate; + private List hobbies = new ArrayList<>(); + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public List getHobbies() { + return hobbies; + } + + public int getBirthYear() { + return 2000 - age; + } + + public void setBirthdate(String b) { + this.birthdate = b; + } + + public String getBirthdate() { + return birthdate; + } + + @Override + public boolean equals(Object o) { + return (o instanceof User) + && Objects.equals(((User) o).name, name) + && ((User) o).age == age; + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } +} diff --git a/src/test/java/java_stream_api/AppTest.java b/src/test/java/java_stream_api/AppTest.java new file mode 100644 index 0000000..4e735d1 --- /dev/null +++ b/src/test/java/java_stream_api/AppTest.java @@ -0,0 +1,451 @@ +package java_stream_api; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.*; +import java.util.stream.*; +import org.junit.jupiter.api.*; + +@DisplayName("App (Java Stream API Examples) Unit Tests - Full Coverage") +class AppTest { + + @Test + @DisplayName("Counts number of elements in the list correctly") + void testFindNumberOfElements() { + assertEquals( + 3, + App.findNumberOfElements(Arrays.asList("a", "b", "c")), + "Should provide correct count of 3"); + assertEquals( + 0, App.findNumberOfElements(Collections.emptyList()), "Empty list should return 0"); + } + + @Test + @DisplayName("Converts all strings to uppercase") + void testConvertStringsToUppercase() { + assertEquals( + Arrays.asList("A", "B"), + App.convertStringsToUppercase(Arrays.asList("a", "b")), + "Lowercase letters should become uppercase"); + } + + @Test + @DisplayName("Filters strings starting with 'A'") + void testFilterStringsStartingWithA() { + assertEquals( + Arrays.asList("Apple", "Axe"), + App.filterStringsStartingWithA(Arrays.asList("Apple", "Axe", "Bob")), + "Only Apple and Axe begin with A"); + } + + @Test + @DisplayName("Finds unique integers") + void testUniqueIntegers() { + assertEquals( + Arrays.asList(1, 2, 3), + App.uniqueIntegers(Arrays.asList(1, 2, 2, 3, 1)), + "Should deduplicate"); + } + + @Test + @DisplayName("Sums integers") + void testSumOfIntegers() { + assertEquals(6, App.sumOfIntegers(Arrays.asList(1, 2, 3)), "Sum should be 6"); + } + + @Test + @DisplayName("Finds minimum integer") + void testMinOfIntegers() { + assertEquals(-2, App.minOfIntegers(Arrays.asList(-2, 1, 0, 5)), "Min should be -2"); + assertEquals( + Integer.MIN_VALUE, + App.minOfIntegers(Collections.emptyList()), + "Empty returns MIN_VALUE"); + } + + @Test + @DisplayName("Finds maximum integer") + void testMaxOfIntegers() { + assertEquals(8, App.maxOfIntegers(Arrays.asList(1, 4, 8)), "Max should be 8"); + assertEquals( + Integer.MAX_VALUE, + App.maxOfIntegers(Collections.emptyList()), + "Empty returns MAX_VALUE"); + } + + @Test + @DisplayName("Joins strings with comma") + void testConcatenateStringsWithComma() { + assertEquals( + "a, b", + App.concatenateStringsWithComma(Arrays.asList("a", "b")), + "Join should be 'a, b'"); + } + + @Test + @DisplayName("Gets first integer or zero") + void testGetFirstIntegerOrZero() { + assertEquals( + 10, + App.getFirstIntegerOrZero(Arrays.asList(10, 20)), + "Should get the first element, 10"); + assertEquals(0, App.getFirstIntegerOrZero(Collections.emptyList()), "Return 0 for empty"); + } + + @Test + @DisplayName("Gets last string or empty") + void testGetLastString() { + assertEquals( + "c", App.getLastString(Arrays.asList("a", "c")), "Should get last string, 'c'"); + assertEquals("", App.getLastString(Collections.emptyList()), "Empty returns ''"); + } + + @Test + @DisplayName("Squares each integer") + void testListOfSquares() { + assertEquals( + Arrays.asList(1, 4, 9), + App.listOfSquares(Arrays.asList(1, 2, 3)), + "Squares should be 1,4,9"); + } + + @Test + @DisplayName("Filters only even numbers") + void testFilterEvenNumbers() { + assertEquals( + Arrays.asList(2, 4), + App.filterEvenNumbers(Arrays.asList(1, 2, 3, 4)), + "Should return [2,4]"); + } + + @Test + @DisplayName("Finds names of users > 18") + void testNamesOfUsersOlderThan18() { + List users = + Arrays.asList(new User("Ann", 19), new User("Bob", 10), new User("Carl", 25)); + assertEquals( + Arrays.asList("Ann", "Carl"), + App.namesOfUsersOlderThan18(users), + "Should retain Ann and Carl"); + } + + @Test + @DisplayName("Sort strings by length") + void testSortStringsByLength() { + assertEquals( + Arrays.asList("z", "yes", "tees"), + App.sortStringsByLength(Arrays.asList("tees", "yes", "z")), + "Should sort by length ascending"); + } + + @Test + @DisplayName("Checks if contains 'Java'") + void testContainsStringWithJava() { + List s1 = Arrays.asList("hi", "Java 8", "b"); + List s2 = Arrays.asList("hi", "xyz"); + assertTrue(App.containsStringWithJava(s1), "'Java' should be found in list"); + assertFalse(App.containsStringWithJava(s2), "'Java' not present, should be false"); + } + + @Test + @DisplayName("Merges two lists") + void testMergeTwoStringLists() { + assertEquals( + Arrays.asList("a", "b", "c"), + App.mergeTwoStringLists(Arrays.asList("a", "b"), Arrays.asList("c")), + "Merged lists"); + } + + @Test + @DisplayName("Averages list of ints") + void testAverageOfIntegers() { + assertEquals( + 1.5, App.averageOfIntegers(Arrays.asList(1, 2)), 0.0001, "Average should be 1.5"); + assertEquals(0.0, App.averageOfIntegers(Collections.emptyList()), "Empty yields avg 0.0"); + } + + @Test + @DisplayName("Discards first three numbers") + void testDiscardFirstThreeIntegers() { + assertEquals( + Arrays.asList(4, 5), + App.discardFirstThreeIntegers(Arrays.asList(1, 2, 3, 4, 5)), + "Should skip first three"); + assertEquals( + Collections.emptyList(), + App.discardFirstThreeIntegers(Arrays.asList(1, 2)), + "Should return empty list if skipped all"); + } + + @Test + @DisplayName("Keeps first three numbers") + void testKeepFirstThreeIntegers() { + assertEquals( + Arrays.asList(1, 2, 3), + App.keepFirstThreeIntegers(Arrays.asList(1, 2, 3, 4, 5)), + "Limit to first three"); + assertEquals( + Arrays.asList(1), + App.keepFirstThreeIntegers(Arrays.asList(1)), + "Less than three returns all"); + } + + @Test + @DisplayName("Flattens list of strings to ASCII codes") + void testStringToAsciiCodes() { + List input = Arrays.asList("Ab"); + List result = App.stringToAsciiCodes(input); + assertEquals(Arrays.asList((int) 'A', (int) 'b'), result, "Should flatten to ASCII codes"); + } + + @Test + @DisplayName("Counts strings longer than 5") + void testCountStringsLongerThan5() { + assertEquals( + 1L, + App.countStringsLongerThan5(Arrays.asList("123", "abcdef")), + "Only 'abcdef' is longer than 5"); + } + + @Test + @DisplayName("Map: String to its length") + void testStringsToLengthMap() { + Map m = App.stringsToLengthMap(Arrays.asList("hey", "there")); + assertEquals(3, m.get("hey"), "hey->3"); + assertEquals(5, m.get("there"), "there->5"); + } + + @Test + @DisplayName("Sorts users by age") + void testSortUsersByAge() { + User u1 = new User("A", 40), u2 = new User("B", 25); + List users = Arrays.asList(u1, u2); + List sorted = App.sortUsersByAge(users); + assertEquals(u2, sorted.get(0), "B is younger than A"); + } + + @Test + @DisplayName("java_stream_api.User with max age") + void testUserWithMaxAge() { + User u1 = new User("A", 40), u2 = new User("B", 25); + assertTrue(App.userWithMaxAge(Arrays.asList(u1, u2)).isPresent(), "Should not be empty"); + assertEquals(u1, App.userWithMaxAge(Arrays.asList(u1, u2)).get(), "A is oldest"); + } + + @Test + @DisplayName("Checks if all strings > 3 len") + void testAreAllStringsLongerThan3() { + assertTrue(App.areAllStringsLongerThan3(Arrays.asList("abcd", "eeee")), "Both > 3"); + assertFalse(App.areAllStringsLongerThan3(Arrays.asList("ab", "abcd")), "One less than 3"); + } + + @Test + @DisplayName("Selects every 3rd element (1-based)") + void testSelectEvery3rd() { + List list = Arrays.asList("A", "B", "C", "D", "E", "F"); + assertEquals( + Arrays.asList("C", "F"), + App.selectEvery3rd(list), + "Should return every 3rd element"); + } + + @Test + @DisplayName("Counts total user hobbies") + void testTotalHobbiesCount() { + User u1 = new User("A", 20), u2 = new User("B", 21); + u1.getHobbies().addAll(Arrays.asList("a", "b")); + u2.getHobbies().addAll(Arrays.asList("c")); + assertEquals( + 3, App.totalHobbiesCount(Arrays.asList(u1, u2)), "Should sum all hobbies (2+1=3)"); + } + + @Test + @DisplayName("Finds strings that appear more than once") + void testDuplicateStrings() { + assertEquals( + Arrays.asList("a"), + App.duplicateStrings(Arrays.asList("a", "b", "a", "c")), + "a appears twice"); + } + + @Test + @DisplayName("Sets user birthdate as AGE MM YYYY") + void testConvertBirthdatesToString() { + User u = new User("AB", 25); + List out = App.convertBirthdatesToString(Arrays.asList(u)); + assertEquals( + "25 MM YYYY", + out.get(0).getBirthdate(), + "Should set birthdate string as '25 MM YYYY'"); + } + + @Test + @DisplayName("Filters persons living in 'City X'") + void testFilterPersonsByCity() { + Person a = new Person("Ann", "City X"), b = new Person("Bob", "City Y"); + List filtered = App.filterPersonsByCity(Arrays.asList(a, b), "City X"); + assertEquals(1, filtered.size(), "Only one person in City X"); + assertEquals(a, filtered.get(0), "Ann is from City X"); + } + + @Test + @DisplayName("Reverses a list") + void testReverseList() { + List input = Arrays.asList(1, 2, 3); + assertEquals(Arrays.asList(3, 2, 1), App.reverseList(input), "Should reverse the list"); + } + + @Test + @DisplayName("Calculates percentage of nulls") + void testPercentageOfNulls() { + List l = Arrays.asList(null, "a", null, "b"); + assertEquals(50, App.percentageOfNulls(l), "2 of 4 are null => 50%"); + assertEquals(0, App.percentageOfNulls(Collections.emptyList()), "Empty returns 0 percent"); + } + + @Test + @DisplayName("Shuffles list in place") + void testShuffleList() { + List list = IntStream.range(1, 6).boxed().collect(Collectors.toList()); + List orig = new ArrayList<>(list); + App.shuffleList(list); + // Can't assert order, just size and content + assertTrue( + list.containsAll(orig) && orig.containsAll(list), + "All elements retained after shuffle"); + } + + @Test + @DisplayName("Groups integers by n%3") + void testGroupByRemainder3() { + List input = Arrays.asList(1, 2, 3, 4, 5, 6); + Map> grouped = App.groupByRemainder3(input); + assertEquals(Arrays.asList(3, 6), grouped.get(0), "Group 0 mod 3"); + assertEquals(Arrays.asList(1, 4), grouped.get(1), "Group 1 mod 3"); + assertEquals(Arrays.asList(2, 5), grouped.get(2), "Group 2 mod 3"); + } + + @Test + @DisplayName("Boolean list: even = true, odd = false") + void testEvenIntegersAsBooleans() { + assertEquals( + Arrays.asList(false, true), + App.evenIntegersAsBooleans(Arrays.asList(1, 2)), + "Even=TRUE, odd=FALSE"); + } + + @Test + @DisplayName("Unique elements reversed") + void testUniqueElementsReversed() { + List in = Arrays.asList(1, 2, 2, 3); + assertEquals(Arrays.asList(3, 2, 1), App.uniqueElementsReversed(in), "Unique reversed"); + } + + @Test + @DisplayName("Returns top 5 of 100 random numbers") + void testTop5Of100Random() { + List list = App.top5Of100Random(); + assertEquals(5, list.size(), "Size is 5"); + for (int i = 1; i < list.size(); ++i) + assertTrue(list.get(i) <= list.get(i - 1), "List should be descending"); + } + + @Test + @DisplayName("Groups strings by length") + void testGroupStringsByLength() { + Map> map = App.groupStringsByLength(Arrays.asList("a", "bb")); + assertEquals(Arrays.asList("a"), map.get(1), "Group of length 1 has 'a'"); + assertEquals(Arrays.asList("bb"), map.get(2), "Group length 2 has 'bb'"); + } + + @Test + @DisplayName("Finds string with largest length") + void testLongestString() { + assertEquals( + "aaaa", App.longestString(Arrays.asList("a", "bb", "aaaa")), "Should be 'aaaa'"); + assertEquals("", App.longestString(Collections.emptyList()), "Empty list returns ''"); + } + + @Test + @DisplayName("Removes names starting with 'J'") + void testRemoveUsersWithJ() { + List in = Arrays.asList("Jim", "Bob", "Jackie"); + assertEquals(Arrays.asList("Bob"), App.removeUsersWithJ(in), "Only Bob remains"); + } + + @Test + @DisplayName("Map: number to its square") + void testIntegersToSquareMap() { + Map m = App.integersToSquareMap(Arrays.asList(2, 3, 4)); + assertEquals(4, m.get(2), "2->4"); + assertEquals(9, m.get(3), "3->9"); + } + + @Test + @DisplayName("Counts total number of all words in sentences") + void testTotalWordsInSentences() { + assertEquals(3, App.totalWordsInSentences(Arrays.asList("a b", "c")), "Total words = 3"); + } + + @Test + @DisplayName("Returns 'yes' if even, 'no' if not") + void testYesNoIfEven() { + List expected = Arrays.asList("no", "yes", "yes"); + assertEquals( + expected, App.yesNoIfEven(Arrays.asList(1, 2, 4)), "Correct 'yes'/'no' mapping"); + } + + @Test + @DisplayName("Calculates range (max-min) in list") + void testRangeOfNumbers() { + assertEquals(9, App.rangeOfNumbers(Arrays.asList(3, 5, 12)), "12-3 = 9"); + assertEquals(0, App.rangeOfNumbers(Collections.emptyList()), "Empty returns 0"); + } + + @Test + @DisplayName("List of string lengths, descending") + void testLengthsDescending() { + List out = App.lengthsDescending(Arrays.asList("a", "bbb", "zz")); + assertEquals(Arrays.asList(3, 2, 1), out, "Sort lengths descending"); + } + + @Test + @DisplayName("Finds sum of all string lengths") + void testSumStringLengths() { + assertEquals(6, App.sumStringLengths(Arrays.asList("abc", "de", "f")), "3+2+1=6"); + } + + @Test + @DisplayName("Counts number of elements equals null") + void testCountNullElements() { + assertEquals( + 2, App.countNullElements(Arrays.asList("a", null, null)), "Count of nulls = 2"); + } + + @Test + @DisplayName("Groups users by year of birth") + void testGroupUsersByBirthYear() { + User u1 = new User("A", 20), u2 = new User("B", 20); + u1.getBirthYear(); + u2.getBirthYear(); // avoid stackoverflow + Map> map = App.groupUsersByBirthYear(Arrays.asList(u1, u2)); + int year = u1.getBirthYear(); + assertTrue(map.containsKey(year), "Should contain year as key"); + assertEquals(2, map.get(year).size(), "Both users in birth group"); + } + + @Test + @DisplayName("Unique, sorted characters from all strings") + void testUniqueSortedCharacters() { + List chars = App.uniqueSortedCharacters(Arrays.asList("bad", "cab")); + assertEquals(Arrays.asList('a', 'b', 'c', 'd'), chars, "Sorted unique: a,b,c,d"); + } + + @Test + @DisplayName("Returns user names sorted by name length") + void testUserNamesSortedByLength() { + User u1 = new User("Eve", 23), u2 = new User("Angelina", 30), u3 = new User("Abi", 19); + List result = App.userNamesSortedByLength(Arrays.asList(u1, u2, u3)); + assertEquals(Arrays.asList("Eve", "Abi", "Angelina"), result, "Sort by length ascending"); + } +}