diff --git a/lesson_10/README.md b/lesson_10/README.md index b52a2f9e..da39f5f2 100644 --- a/lesson_10/README.md +++ b/lesson_10/README.md @@ -1,9 +1,23 @@ # Lesson 10 +## Quiz Instructions + +1. Sync your fork and create a new branch for your quiz. +2. Terminal into the `quiz` sub-directory and run the following command to take the quiz interactively: +```bash +./gradlew run --console=plain +``` +3. If you would like to check your answers, you can run the following command: +```bash +./gradlew test -Dprofile=prod +``` +4. Submit a PR with your response. Your last submission up to the cutoff deadline will be accepted (3/20/24 @ 1:20 PM ET). + ## Homework -* TODO(anthonydmays): Add details +* Read HFDP 1-2. +* Complete [Applying SOLID principles](#applying-solid-principles) exercise. -## Custom Data Types +## Applying SOLID Principles * TODO(anthonydmays): Add details diff --git a/lesson_10/quiz/quiz_app/build.gradle.kts b/lesson_10/quiz/quiz_app/build.gradle.kts index f4b18cef..538cebd6 100644 --- a/lesson_10/quiz/quiz_app/build.gradle.kts +++ b/lesson_10/quiz/quiz_app/build.gradle.kts @@ -44,6 +44,9 @@ tasks.named("test") { if (System.getProperty("profile") != null) { systemProperty("spring.profiles.active", System.getProperty("profile")) } + if (System.getProperty("quizTaker") != null) { + systemProperty("quiz.quizTaker", System.getProperty("quizTaker")) + } } diff --git a/lesson_10/quiz/quiz_app/src/main/java/com/codedifferently/quiz/lesson10/Lesson10.java b/lesson_10/quiz/quiz_app/src/main/java/com/codedifferently/quiz/lesson10/Lesson10.java index af420803..1d4008d8 100644 --- a/lesson_10/quiz/quiz_app/src/main/java/com/codedifferently/quiz/lesson10/Lesson10.java +++ b/lesson_10/quiz/quiz_app/src/main/java/com/codedifferently/quiz/lesson10/Lesson10.java @@ -9,10 +9,9 @@ import java.io.IOException; import java.nio.file.Paths; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Scanner; -import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; @@ -70,12 +69,15 @@ private String promptForFileName(Scanner scanner) { } private void saveAnswersToFile(List questions, String filename) { - Map values = - questions.stream() - .collect(Collectors.toMap(QuizQuestion::getQuestionNumber, QuizQuestion::getAnswer)); + var values = new LinkedHashMap(); + for (QuizQuestion question : questions) { + values.put(question.getQuestionNumber(), question.getAnswer()); + } + var file = new File(getDataPath() + File.separator + filename + ".json"); file.getParentFile().mkdirs(); var gson = new GsonBuilder().setPrettyPrinting().create(); + try (var writer = new FileWriter(file, false)) { writer.write(gson.toJson(values)); } catch (IOException e) { diff --git a/lesson_10/quiz/quiz_app/src/main/resources/application.yml b/lesson_10/quiz/quiz_app/src/main/resources/application.yml index 26314528..dbcf571e 100644 --- a/lesson_10/quiz/quiz_app/src/main/resources/application.yml +++ b/lesson_10/quiz/quiz_app/src/main/resources/application.yml @@ -4,149 +4,244 @@ spring: quiz: questions: default: - - prompt: "What is the DRY principle about?" - choices: - A: "An OOP principle about developing realistic YAML configuration values." - B: "Preventing the duplication of the same thing in multiple places." - C: "A means for defining interfaces in an object-oriented system." - D: "'Do Repeat Yourself': It advocates for writing code that repeats throughout the application for easier understanding." - - - prompt: "What does the concept of Inheritance in OOP represent?" - choices: - A: "The ability to derive a class from multiple base classes." - B: "The ability of a class to include properties and methods of another class." - C: "The ability of a class to hide its internal implementation." - D: "The ability of objects to take on many forms." - - - prompt: "What does the term 'Abstraction' mean in the context of OOP?" - choices: - A: "Removing the features from a class that makes it unique." - B: "The process of simplifying and hiding complexity." - C: "The act of inheriting from more than one class." - D: "Combining data and functions that operate on that data into a single unit." - - - prompt: "What is a Class in OOP?" - choices: - A: "An instance of an object." - B: "A special function that creates objects containing data and behavior." - C: "A method that is automatically called when an object is created." - D: "A blueprint from which objects are created that combine data and behavior." - - - prompt: "Which concept of OOP allows different classes to be treated as instances of the same class through a common interface?" - choices: - A: "Inheritance" - B: "Encapsulation" - C: "Polymorphism" - D: "Abstraction" - - - prompt: "When changes in one part of a system force changes in another part, this is an indication of what?" - choices: - A: "High coupling" - B: "High cohesion" - C: "Low coupling" - D: "Low cohesion" - - - prompt: "When storing numbers that require high precision in Java, which data type is best to use?" - choices: - A: "long" - B: "double" - C: "decimal" - D: "float" - - - prompt: "Which data structure is great for random access?" - choices: - A: "Linked list" - B: "Set" - C: "Array" - D: "Tree" - - - prompt: "Which data structure is optimized for 'last in, first out' operation?" - choices: - A: "Stack" - B: "Queue" - C: "Tree" - D: "Array" - - - prompt: "What method must you include in your Java application in order to run your application?" - choices: - A: "constructor App()" - B: "public void main(String[] args)" - C: "public static enum App" - D: "public static void main(String[] args)" - - - prompt: "Which line of code creates an object instance for a class called `Test` with a single parameter?" - choices: - A: "Test obj = new Test(123);" - B: "Object test = new Object(\"param1\");" - C: "Test val = Test.PARAM1;" - D: "@Test testClass(Param value)" - - - prompt: "The Java programming language is a:" - choices: - A: "Dynamically typed language" - B: "Strongly typed language" - C: "Weakly typed language" - D: "Storage typed language" - - - prompt: "What keyword do you use if you want to get out of a loop before it finishes:" - choices: - A: "for" - B: "while" - C: "interrupt" - D: "break" - - - prompt: "Choose the line of code that shows a class inheriting another class:" - choices: - A: "class Foo implements Bar {}" - B: "class Foo extends Bar {}" - C: "class Foo inherits Bar {}" - D: "class Foo abstracts Bar {}" - - - prompt: "Which git command should you use to restore a file to a previous commit?" - choices: - A: "git checkout" - B: "git stash" - C: "git commit" - D: "git revert" - - - prompt: "What's the name of branch intended for use when implementing new features?" - choices: - A: "A feature branch" - B: "A forked branch" - C: "A main branch" - D: "A clone branch" - - - prompt: "What is the purpose of the `git clone` command?" - choices: - A: "To create a new branch in the repository." - B: "To copy a git repository from a remote source to your local machine." - C: "To merge changes from one branch to another." - D: "To stage changes for the next commit." - - - prompt: "In what order do `for` loop iterations run?" - choices: - A: "(1) increment, (2) initialization, (3) condition, (4) loop body" - B: "(1) increment, (2) condition, (3) initialization, (4) loop body" - C: "(1) initialization, (2) loop body, (3) condition, (4) increment" - D: "(1) initialization, (2) condition, (3) loop body, (4) increment" - - - prompt: "To skip to the next loop iteration, what keyword should you use?" - choices: - A: "return" - B: "break" - C: "continue" - D: "goto" - - - prompt: "Which of the following options are in lower camel case?" - choices: - A: "lowerCamelCase" - B: "lower_camel_case" - C: "Lower_Camel_Case" - D: "LowerCamelCase" - - - prompt: "Which of the following options are in upper case snake case?" - choices: - A: "snakeCase" - B: "SNAKE_CASE" - C: "Snake_Case" - D: "SnakeCase" + - prompt: "Which keyword is used to declare a variable in Java?" + choices: + A: "let" + B: "variable" + C: "const" + D: "int" + + - prompt: "What is the difference between a class and an object in Java?" + choices: + A: "A class is a collection of objects, while an object is an instance of a class." + B: "A class is used for inheritance, while an object is used for polymorphism." + C: "A class is a blueprint for creating objects, while an object is a collection of classes." + D: "A class is a data type, while an object is a method." + + - prompt: "Which data type is used to store whole numbers in Java?" + choices: + A: "boolean" + B: "String" + C: "double" + D: "long" + + - prompt: "What is the correct syntax for declaring a string variable in Java?" + choices: + A: "String name = \"John\";" + B: "string name = 'John';" + C: "String name = 'John';" + D: "string name = \"John\";" + + - prompt: "What is the purpose of the 'if' statement in Java?" + choices: + A: "To repeat a block of code a specific number of times." + B: "To execute a block of code only if a certain condition is true." + C: "To define a method in a class." + D: "To declare a variable." + + - prompt: "Which operator is used to compare two values for equality in Java?" + choices: + A: "!=" + B: ">" + C: "==" + D: "=" + + - prompt: "What is the purpose of the 'for' loop in Java?" + choices: + A: "To execute a block of code only if a certain condition is true." + B: "To repeat a block of code a specific number of times." + C: "To define a method in a class." + D: "To declare a variable." + + - prompt: "Which data type is used to store decimal numbers in Java?" + choices: + A: "boolean" + B: "String" + C: "int" + D: "double" + + - prompt: "What is the purpose of the 'while' loop in Java?" + choices: + A: "To execute a block of code only if a certain condition is true." + B: "To define a method in a class." + C: "To repeat a block of code as long as a certain condition is true." + D: "To declare a variable." + + - prompt: "What is the purpose of the 'switch' statement in Java?" + choices: + A: "To repeat a block of code a specific number of times." + B: "To declare a variable." + C: "To define a method in a class." + D: "To select one of many code blocks to be executed." + + - prompt: "Which data type is used to store true or false values in Java?" + choices: + A: "int" + B: "double" + C: "String" + D: "boolean" + + - prompt: "What is the correct syntax for declaring an integer variable in Java?" + choices: + A: "integer num = '10';" + B: "int num = 10;" + C: "integer num = 10;" + D: "int num = '10';" + + - prompt: "What is the purpose of the 'else' statement in Java?" + choices: + A: "To repeat a block of code a specific number of times." + B: "To declare a variable." + C: "To define a method in a class." + D: "To execute a block of code if the 'if' condition is false." + + - prompt: "Which data type is used to store text in Java?" + choices: + A: "String" + B: "int" + C: "double" + D: "boolean" + + - prompt: "What is the correct syntax for declaring a double variable in Java?" + choices: + A: "double num = '3.14';" + B: "double num = 3,14;" + C: "double num = \"3.14\";" + D: "double num = 3.14;" + + - prompt: "What is encapsulation in object-oriented programming?" + choices: + A: "Encapsulation is the process of creating multiple instances of a class." + B: "Encapsulation is the process of defining a class." + C: "Encapsulation is the process of hiding internal data and methods of an object and providing access to it only through public methods." + D: "Encapsulation is the process of inheriting properties and behaviors from a parent class." + + - prompt: "What is inheritance in object-oriented programming?" + choices: + A: "Inheritance is the process of creating multiple instances of a class." + B: "Inheritance is the process of defining a class." + C: "Inheritance is the process of hiding internal data and methods of an object and providing access to it only through public methods." + D: "Inheritance is the process of inheriting properties and behaviors from a parent class." + + - prompt: "What is polymorphism in object-oriented programming?" + choices: + A: "Polymorphism is the process of creating multiple instances of a class." + B: "Polymorphism is the process of defining a class." + C: "Polymorphism is the process of hiding internal data and methods of an object and providing access to it only through public methods." + D: "Polymorphism is the process of using a single interface to represent different types of objects." + + - prompt: "What is abstraction in object-oriented programming?" + choices: + A: "Abstraction is the process of creating multiple instances of a class." + B: "Abstraction is the process of simplifying complex systems by breaking them down into smaller, more manageable parts." + C: "Abstraction is the process of defining a class." + D: "Abstraction is the process of hiding internal data and methods of an object and providing access to it only through public methods." + + - prompt: "Which principle of object-oriented programming allows objects of different classes to be treated as objects of the same class?" + choices: + A: "Inheritance" + B: "Polymorphism" + C: "Encapsulation" + D: "Abstraction" + + - prompt: "What is the naming convention for classes in Java?" + choices: + A: "camelCase" + B: "PascalCase" + C: "snake_case" + D: "kebab-case" + + - prompt: "What is the naming convention for variables in Java?" + choices: + A: "PascalCase" + B: "camelCase" + C: "snake_case" + D: "kebab-case" + + - prompt: "What is the naming convention for methods in Java?" + choices: + A: "PascalCase" + B: "snake_case" + C: "kebab-case" + D: "camelCase" + + - prompt: "What is the naming convention for packages in Java?" + choices: + A: "PascalCase" + B: "snake_case" + C: "lowercase" + D: "kebab-case" + + - prompt: "What is Git?" + choices: + A: "A programming language commonly used for web development." + B: "A version control system used for tracking changes in files and coordinating work among multiple people." + C: "A database management system for storing and retrieving data." + D: "A software development methodology for agile project management." + + - prompt: "What is a commit in Git?" + choices: + A: "A software tool used for analyzing and optimizing code." + B: "A command used to merge branches in Git." + C: "A record of changes made to a repository at a specific point in time." + D: "A file that contains the source code of a program." + + - prompt: "What is a branch in Git?" + choices: + A: "A command used to create a new repository in Git." + B: "A separate line of development that allows you to work on a feature or bug fix without affecting the main codebase." + C: "A file that contains the configuration settings for a program." + D: "A software tool used for managing dependencies in a project." + + - prompt: "What is a merge conflict in Git?" + choices: + A: "A command used to discard changes and revert to a previous version in Git." + B: "A file that contains the documentation and instructions for using a program." + C: "A situation that occurs when Git is unable to automatically merge changes from different branches." + D: "A software tool used for profiling and optimizing code performance." + + - prompt: "What command should you use to restore a file to its state at an earlier commit?" + choices: + A: "git reset " + B: "git checkout " + C: "git restore " + D: "git revert " + + - prompt: "What Git command do you use to create a new branch?" + choices: + A: "git checkout -b " + B: "git branch " + C: "git commit -m 'Create branch'" + D: "git merge " + answers: + default: + - $2y$10$mhwamqUPf8AlI2N9UNSOve/PNRo1aKKRXGVVyuAZmXTByDKjE7Htm + - $2y$10$VHv7.t7MLdDE8Fd2Hqo.oOhH0VUfu6jT2aZRPaeWypmZb9YYTjOQK + - $2y$10$XKYYo.Kqr3OH9taIQ3ktWeby29gt1EWQqI652O3Olim5thHd7MmDm + - $2y$10$KfuFshyYl.EMU8/R6UgZeOTjgRctSejlttkAaQxRLw7bcriMbC/BO + - $2y$10$IjYrvmc.kHlQl1RgOx5czOZBSWIt17PDhbzqQ4y34wBVKUOv7ndM6 + - $2y$10$I3iiNwXF8a1/NlhonKKhKeykCUKF8JbfYmfSe/Fnm9BFyyvxJWTYK + - $2y$10$AoEJX6ZNU3M/drohEN9FQ.TGDM/sCCyaRLVIquzZ9aBpF0nGbXY5q + - $2y$10$2XgmrcrXQhdIEVg4VG2kmOJ7q4SsQ5m7ADBP7OoTrYzHdd.zVsVYe + - $2y$10$xDqH8PMa29gEBZLyzSNwH.zVjsMlSw0S9xKP4hirXpCUkGPpV4OCO + - $2y$10$/bYGhp..VtYS.WLkUxl0CeKCPfxazFib.dIDKffpZHn9vcRRMIYXe + - $2y$10$iDtgVSWSR.pT2e3RIIkWq./.wr.rd8OEyRyE.L5.hjPXzHknlU1w2 + - $2y$10$3X1snpG9.yaWfCIJvO60W.EiKjsNYPC1y6h6DjI.4t.sy1TYh5WqG + - $2y$10$.eRBNLeZnI7/gcrlvKjbK.MqBvcMAng7Xwb5meNoA2psW4osaWTSq + - $2y$10$BVgsKcyAupOvIs3PENI8VuXDpcLT79WCvAKCL3lasIko1xOySVCba + - $2y$10$cQaUh8BtUxyA.Uy4I6fTV.jy9pvOQlUlWJCXkmdA/hXFSe.hXkneu + - $2y$10$cbSbw.rKDqRcKpEjzxWLHeGZ05b/UeIlRwpQAiFgaJmyPHJ.ruCt6 + - $2y$10$eeKtu6LJx7qsFO/DqH/TQ.6loAKI6tJjgXQtqjxazA3z.NKQeyTku + - $2y$10$YG066HQb9BwlOzi2vcRpKeSDShaeE8SPlOzhAtPMVhvCYEW6qS4q2 + - $2y$10$LME4LyliAhiVxD6BtkzsQuLuG5zLjydoarE9r2dSw.3Nb6aGWT.fC + - $2y$10$IL3165Mie6PPSdQ61keHm.e7t1lzFH5RZOkq5kFwrKNJBLAOPi89u + - $2y$10$5xUEwhWf.47OVHhP1ForuuFKqFto0ZGAnZNpe7DS1dhw3Imq91qye + - $2y$10$G0l0E4QQQkAupN92Y.2hTetAhIeq1C0hOhDUZvE/Vb3rTsvWqBUIO + - $2y$10$9h4YJXOcBYFUTg5SbWvWG.OpNOAIREXYd0zUCsojizdoFr0dkpK9C + - $2y$10$9jCWir.loewv48CkBGTpKOF5BdffKHET7134v1eXRxI.BI6JAiwtK + - $2y$10$TVAUHe1Qnfp9HBrLKaXoaeOcgogKCOh75Xl0g4slyGE59q2OuzLIW + - $2y$10$IbU1hFYURn2c/3n3vU1EiulH/J7RiYbRJZqntaJuFeF5SiYiK87ju + - $2y$10$Tn7OfgalNswMFsDDYqg0se65LbgDIitoI5r/.NqrbGlbWnG0wZAh. + - $2y$10$N6tLPnI/ME0fct9ELNNqNe5gHye3mtBh7LHfduIhsPEELSAROvBri + - $2y$10$k2Pb2AIjqMcPBxhauVo2fuRNuzQnje7w/wTs6vhf2X/jKdYSWBkJa + - $2y$10$ccOFeGlKvjS24vEbry0jT.LWTGdQ5Z641XCf2FSPTuF7x9PN4RJw6 diff --git a/lesson_10/quiz/quiz_app/src/main/resources/data/anthonymays.json b/lesson_10/quiz/quiz_app/src/main/resources/data/anthonymays.json index e1c7f7b9..b86c6153 100644 --- a/lesson_10/quiz/quiz_app/src/main/resources/data/anthonymays.json +++ b/lesson_10/quiz/quiz_app/src/main/resources/data/anthonymays.json @@ -1,17 +1,17 @@ { - "0": "", - "1": "", - "3": "", - "4": "", "5": "", - "7": "", - "8": "", "9": "", - "10": "", - "13": "", - "15": "", + "3": "", + "8": "", + "1": "", + "19": "", + "7": "", + "11": "", + "0": "", "16": "", "17": "", - "18": "", - "20": "" -} + "10": "", + "13": "", + "12": "", + "6": "" +} \ No newline at end of file diff --git a/lesson_10/quiz/quiz_app/src/test/java/com/codedifferently/quiz/lesson10/Lesson10Test.java b/lesson_10/quiz/quiz_app/src/test/java/com/codedifferently/quiz/lesson10/Lesson10Test.java index a73b94ac..132d7e3b 100644 --- a/lesson_10/quiz/quiz_app/src/test/java/com/codedifferently/quiz/lesson10/Lesson10Test.java +++ b/lesson_10/quiz/quiz_app/src/test/java/com/codedifferently/quiz/lesson10/Lesson10Test.java @@ -1,6 +1,7 @@ package com.codedifferently.quiz.lesson10; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; import com.codedifferently.instructional.quiz.MultipleChoiceQuizQuestion; import com.codedifferently.instructional.quiz.QuizConfig; @@ -16,7 +17,12 @@ import java.util.List; import java.util.Map; import java.util.stream.Stream; +import org.assertj.core.api.SoftAssertions; +import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ContextConfiguration; @@ -24,8 +30,20 @@ @SpringBootTest @ContextConfiguration(classes = Lesson10.class) +@ExtendWith(SoftAssertionsExtension.class) class Lesson10Test { @Autowired private QuizConfig quizConfig; + private SoftAssertions softly; + + @BeforeEach + void setUp() { + softly = new SoftAssertions(); + } + + @AfterEach + void tearDown() { + softly.assertAll(); + } @Test void testQuiz_questionConfigured() { @@ -44,16 +62,36 @@ void testQuiz_questionConfigured() { @Test @EnabledIf(value = "#{environment.getActiveProfiles()[0] == 'prod'}", loadContext = true) void checkQuestions_answeredCorrectly() throws Exception { + List questions = quizConfig.getQuestions("default"); List paths = getResponseFilePaths(); + var quizTaker = quizConfig.getQuizTaker(); + var answersFound = false; for (Path path : paths) { + if (!quizTaker.isEmpty() + && !path.getFileName().toString().contains(quizConfig.getQuizTaker())) { + continue; + } Map responses = getResponsesFromPath(path); for (var entry : responses.entrySet()) { Integer questionNumber = entry.getKey(); - String response = entry.getValue(); - boolean result = quizConfig.checkAnswer("default", questionNumber, response); - assertThat(result).isEqualTo(true); + QuizQuestion question = questions.get(questionNumber); + String actualAnswer = entry.getValue(); + answersFound = true; + + // Check that the answer is correct. + softly + .assertThat(quizConfig.checkAnswer("default", questionNumber, actualAnswer)) + .as( + "Checking answer is correct for question " + + questionNumber + + ": " + + question.getQuestionPrompt()) + .isTrue(); } } + if (!answersFound) { + fail("No answers found to check."); + } } private static List getResponseFilePaths() { diff --git a/lib/java/codedifferently-instructional/instructional-lib/src/main/java/com/codedifferently/instructional/quiz/QuizConfig.java b/lib/java/codedifferently-instructional/instructional-lib/src/main/java/com/codedifferently/instructional/quiz/QuizConfig.java index 89b312d4..3b33c459 100644 --- a/lib/java/codedifferently-instructional/instructional-lib/src/main/java/com/codedifferently/instructional/quiz/QuizConfig.java +++ b/lib/java/codedifferently-instructional/instructional-lib/src/main/java/com/codedifferently/instructional/quiz/QuizConfig.java @@ -19,11 +19,20 @@ public class QuizConfig { private Map> answersByProvider; private Map> questionsByProvider; private Verifyer verifyer = BCrypt.verifyer(); + private String quizTaker = ""; public void setAnswers(Map> answersByProvider) { this.answersByProvider = answersByProvider; } + public void setQuizTaker(String quizTaker) { + this.quizTaker = quizTaker; + } + + public String getQuizTaker() { + return this.quizTaker; + } + public void setQuestions(Map> questionsByProvider) { if (questionsByProvider == null) { this.questionsByProvider = new HashMap<>();