Skip to content

Conversation

@HDPark95
Copy link
Owner

@HDPark95 HDPark95 commented May 17, 2025

실전 자바 소프트웨어 개발

문서관리 시스템

학습 키워드

  • 상속보다 조합

→ 상속을 통해서 객체간의 관계를 표현하게 되면 Is-a 관계를 가지게 된다.

단점 : 부모의 변경이 자식에 영향이 간다. 부모 기능 중 필요하지 않는 기능까지 물려받는다.

조합 : 스프링의 주입과 같은 방식으로 필드로 추가.

필요한 기능만 선택적으로 사용할 수 있고, 여러 객체에서 재사용할 수 있다.

⇒ 상속은 변경에 유연하지 않음. 느슨하게 결합해야 변경에 유연함.

  • 강한 형식의 원칙

String 대신 File객체를 사용해서 오류가 발생할 확률을 줄인다.

추가로 불변객체를 사용하여, 오류가 발생하였을 때 오류 발생 원인을 축소할 수 있다.

  • 유비쿼터스 언어

개발자와 사용자 모두가 사용할 수 있도록 설계, 공유된 공통 언어를 의미함.

실무에서, 실무자가 사용하는 언어를 사용해야 소통하고 코드 발견성을 향상 시킬 수 있음.

디자인팀, 기획팀, 개발팀이 다른 용어를 사용하면 혼선이나 오해가 있을 수 있고 발견성이 떨어짐.

  • KISS 원칙

가능한 단순하게 해라

누군가 어쩌면 이런 기능이 필요할지 몰라요, Y도 할 수 있으면 좋을 텐데요 같은 말에 아니요라고 대답해야함. 좋은 의도를 가진 확장성 반드시 필요한 기능을 구현해야함. 있으면 좋은 기능을 추가하다보면 설계가 얼룩지고 복잡해짐.

  • 리스코프 치환 원칙

클래스 상속와 인터페이스 구현을 올바르게 사용하도록 도와주는 원칙

  1. 하위 형식은 선행 조건을 더할 수 없음.

    부모의 선행조건을 자식이 추가할 수 없다.

  2. 하위 형식에서 후행 조건을 약화시킬 수 없음.

    특정 코드가 수행된 뒤 만족해야하는 조건을, 부모자식 모두 만족해야한다.

  3. 슈퍼 형식의 불변자는 하위 형식에서 보존됨

    부모의 필드를 자식에서 변경할 수 있으면 안된다.

  4. 히스토리 규칙

    자식 클래스는 부모가 예상한대로 동작의 흐름과 변경을 유지해야한다.

    부모의 동작을 무력화하거나, 무의미하게 만드는건 안된다.

  • 코드를 재사용하기 위한 세가지 방법

    1. 유틸리티 클래스

      유틸클래스는 구현하기는 간편하나, 점차 여러 정적메서드를 포함하게되고 갓 클래스의 모양을 갖추는 안티패턴이 된다.

    2. 상속

      재사용을 위해 상속을 사용하면 관계가 깨질 확률이 높음

    3. 도메인 클래스

      상속받는 클래스가 아닌 도메인 클래스를 별도로 만들어서, 해당 클래스를 재사용하는 방법

      할인 정책 같은 것을 도메인 클래스로 사용해서 정책 클래스를 많이 사용

  • 테스트 위생

    1. 공개된 동작에 대해서만 테스트

    커버리지 관련된 내용, 통합 테스트만 하는 것이 옳은가? 책에서는 단위테스트를 하지 않음.

    1. 테스트 명 읽기 좋게

      대체로 한글명으로도 작성하고 displayName 어노테이션으로 테스트에 대해 표현함.

    2. 실패 케이스에 대해 작성

      정책상 무조건 실패해야한다면 실패케이스들 위주로 작성하는 편

Summary by CodeRabbit

  • New Features

    • Introduced a document management system with support for importing and searching various document types (letters, reports, images, invoices).
    • Added extensible importer framework for handling new document types.
    • Enabled attribute-based document search functionality.
    • Provided comprehensive documentation and conceptual design notes for the document management system.
  • Bug Fixes

    • None.
  • Documentation

    • Added user and developer guides, including conceptual overviews and challenge sections.
  • Tests

    • Introduced automated tests covering document import, attribute extraction, searching, and error handling.
    • Generated test reports in HTML, XML, and summary formats for test results visibility.
  • Chores

    • Set up Gradle build scripts and wrapper for project automation.
    • Added configuration files and initial empty classes/interfaces for future HTTP server features.
    • Updated server configuration to increase Tomcat thread limits for improved performance.

@coderabbitai
Copy link

coderabbitai bot commented May 17, 2025

Walkthrough

This update introduces a comprehensive document management system example for educational purposes, including conceptual documentation, Java source code, and a complete Gradle project setup with tests and reports. Additional minor changes include the creation of placeholder classes for networking and servlet infrastructure, a percent encoding demonstration, and minor configuration and logging adjustments in other unrelated modules.

Changes

File(s) / Path(s) Change Summary
book/real-world-software-development/chapter4/README.md Added conceptual notes and design considerations for a document management system.
book/real-world-software-development/chapter4/document-management/build.gradle.kts, settings.gradle.kts, gradlew, gradlew.bat, gradle/wrapper/gradle-wrapper.properties Added Gradle build scripts, settings, and wrapper for project automation and reproducibility.
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java Introduced a constants class for attribute keys.
book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java Added a document class encapsulating attributes.
book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java Implemented the main document management logic: import, search, and storage.
book/real-world-software-development/chapter4/document-management/src/main/java/project/Importer.java Defined the importer interface for extensible file handling.
book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java, InvoiceImporter.java, LetterImporter.java, ReportImporter.java Added file type-specific importer implementations.
book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java Implemented a query parser and predicate for searching documents.
book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java Added a text file helper for parsing and attribute extraction.
book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java Introduced a custom exception for unsupported file types.
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java Added comprehensive JUnit tests for document import, attribute extraction, search, and error handling.
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/..., build/test-results/test/TEST-chpater4.DocumentManagementSystemTest.xml Added generated test reports (HTML, XML, CSS, JS) summarizing test outcomes and failures.
simple-java/docs/chapter4.md Added a placeholder markdown file for a document management challenge.
javav-network/src/main/java/project/reflect/caculator/Calculator.java, was/httpserver/HttpRequest.java, HttpResponse.java, HttpServlet.java, ServletManager.java, servlet/NotFoundServlet.java, was/v3/PercentEncodingMain.java, was/v5/servlet/HttpServlet.java Added empty or demonstration classes/interfaces for HTTP server and percent encoding.
thread-pool-optimization/k6/io_user_test.js Enhanced HTTP status check with conditional logging for failures.
thread-pool-optimization/src/main/java/project/threadpooloptimization/interfaces/UserController.java Added Spring framework imports to the controller class.
thread-pool-optimization/src/main/resources/application.yml Increased Tomcat thread pool size and commented out the accept-count setting.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DocumentManagementSystem
    participant Importer
    participant Document

    User->>DocumentManagementSystem: importFile(path)
    DocumentManagementSystem->>Importer: importFile(file)
    Importer-->>Document: (creates Document with attributes)
    Importer-->>DocumentManagementSystem: return Document
    DocumentManagementSystem-->>User: (Document added to contents)

    User->>DocumentManagementSystem: search(query)
    DocumentManagementSystem->>Document: getAttribute()
    DocumentManagementSystem-->>User: return matching Documents
Loading

Poem

🐇
In the warren of code, new docs take their place,
With imports and queries, each type has its space.
Tests run and report, though some files are missed,
While servers and threads on the sidelines exist.
A hop, a leap, extensibility's cheer—
The system grows stronger, springing forward this year!

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 25

🧹 Nitpick comments (34)
thread-pool-optimization/k6/io_user_test.js (1)

16-22: Great enhancement to error diagnostics!

The modification to the status check improves observability by adding detailed error logging while preserving the original functionality. When an HTTP request fails, you'll now see the status code, status text, and response headers, making debugging much easier.

A small suggestion for even better diagnostics would be to include the response body in the error log for cases where the API returns error details in the body.

 'status is 200': (r) => {
     const ok = r.status === 200;
     if (!ok) {
-        console.log(`❌ 실패 응답: ${r.status} ${r.status_text}, headers: ${JSON.stringify(r.headers)}`);
+        console.log(`❌ 실패 응답: ${r.status} ${r.status_text}, headers: ${JSON.stringify(r.headers)}, body: ${r.body}`);
     }
     return ok;
 },
javav-network/src/main/java/project/reflect/caculator/Calculator.java (1)

3-5: Add class-level Javadoc stub.

As an empty placeholder class, include a brief Javadoc describing its intended role or planned methods. This improves discoverability and sets clear expectations for future development. For example:

/**
 * Calculator provides core arithmetic operations for reflection-based utilities.
 * <p>
 * Future implementations may include methods like add, subtract, multiply, and divide.
 * </p>
 */
public class Calculator {
    // ...
}
javav-network/src/main/java/project/was/v3/PercentEncodingMain.java (2)

9-10: Consider renaming variables for clarity.
To improve readability, rename encodeencoded (or encodedString) and decodedecoded (or decodedString), since these store processed values.

Proposed diff:

-        String encode = URLEncoder.encode("가%", StandardCharsets.UTF_8);
+        String encoded = URLEncoder.encode("가%", StandardCharsets.UTF_8);

-        System.out.println("encode = " +  encode);
+        System.out.println("encoded = " + encoded);

-        String decode = URLDecoder.decode(encode, StandardCharsets.UTF_8);
+        String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);

-        System.out.println("decode = " + decode);
+        System.out.println("decoded = " + decoded);

Also applies to: 12-13


7-8: Add a brief class-level Javadoc.
Since this is a public utility/demo, a short Javadoc enhances discoverability in IDEs and generated docs.

Proposed addition:

+/**
+ * Demonstrates percent-encoding and decoding of a sample string using UTF-8.
+ */
 public class PercentEncodingMain {
thread-pool-optimization/src/main/java/project/threadpooloptimization/interfaces/UserController.java (1)

9-11: Remove or justify unused imports
The imports HandlerMethod, RequestMappingHandlerAdapter, and RequestMappingHandlerMapping are not used anywhere in this controller. Unused imports increase clutter and can confuse maintainers. If they’re planned for imminent use, please add a comment explaining their purpose; otherwise, remove them.

thread-pool-optimization/src/main/resources/application.yml (1)

4-6: Clarify the commented accept-count setting
Commenting out accept-count: 300 causes Tomcat to revert to its default backlog (usually 100). If you intend to support a backlog of 300 connections, uncomment or explicitly set this value. Otherwise, consider removing the commented line to avoid confusion.

javav-network/src/main/java/project/was/httpserver/ServletManager.java (2)

11-13: Consider adding validation in the add method.

The current implementation allows overwriting existing servlet mappings without any warning or validation. Consider adding validation to prevent accidentally overwriting existing mappings or to explicitly document this behavior.

public void add(String path, HttpServlet servlet){
+    if (servletMap.containsKey(path)) {
+        // Option 1: Throw exception
+        // throw new IllegalArgumentException("Servlet mapping already exists for path: " + path);
+        
+        // Option 2: Log warning
+        // System.out.println("Warning: Overwriting existing servlet mapping for path: " + path);
+    }
+    if (servlet == null) {
+        throw new IllegalArgumentException("Servlet cannot be null");
+    }
    servletMap.put(path, servlet);
}

1-22: Add JavaDoc comments for better documentation.

The class and its methods lack documentation. Adding JavaDoc comments would improve code maintainability and help other developers understand the purpose and usage of this class.

package project.was.httpserver;

import java.util.HashMap;
import java.util.Map;

+/**
+ * Manages servlet registrations and dispatches HTTP requests to the appropriate servlet.
+ * Serves as the central registry for mapping URL paths to servlet instances.
+ */
public class ServletManager {

    private final Map<String, HttpServlet> servletMap = new HashMap<>();

+    /**
+     * Registers a servlet for a specific URL path.
+     * 
+     * @param path The URL path to map the servlet to
+     * @param servlet The servlet instance to handle requests to the specified path
+     */
    public void add(String path, HttpServlet servlet){
        servletMap.put(path, servlet);
    }

+    /**
+     * Executes the appropriate servlet based on the incoming request.
+     * If no servlet is registered for the requested path, a 404 response is generated.
+     * 
+     * @param request The HTTP request to process
+     * @param response The HTTP response to populate
+     */
    public void execute(HttpRequest request, HttpResponse response){
        try{

        }catch (Exception e){

        }
    }
}
book/real-world-software-development/chapter4/document-management/gradle/wrapper/gradle-wrapper.properties (1)

1-6: Timestamp in the future detected

The timestamp in line 1 shows "Sat May 17 10:03:06 KST 2025" which appears to be in the future. While this doesn't affect functionality, it might indicate an incorrect system clock when this file was generated.

Otherwise, the Gradle wrapper configuration is standard and correctly configured with Gradle 8.5.

book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)

4-14: Good use of constants class but add private constructor

Centralizing string constants is good practice to prevent duplication and typos. However, utility classes with only static members should typically have a private constructor to prevent instantiation.

Add a private constructor to prevent instantiation:

 public final class Attributes
 {
+    private Attributes() {
+        // Prevents instantiation
+    }
+
     public static final String PATH = "path";
     public static final String PATIENT = "patient";
     public static final String ADDRESS = "address";
     public static final String BODY = "body";
     public static final String WIDTH = "width";
     public static final String HEIGHT = "height";
     public static final String TYPE = "type";
     public static final String AMOUNT = "amount";
 }
book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java (2)

12-14: Add null check and consider additional methods

The getAttribute method should validate the input parameter. Also, consider adding methods to check if an attribute exists or to get all attributes.

Add null validation and consider additional helper methods:

     public String getAttribute(final String attributeName) {
+        if (attributeName == null) {
+            throw new IllegalArgumentException("Attribute name cannot be null");
+        }
         return attributes.get(attributeName);
     }
+
+    public boolean hasAttribute(final String attributeName) {
+        return attributeName != null && attributes.containsKey(attributeName);
+    }
+
+    public Map<String, String> getAttributes() {
+        return new HashMap<>(attributes);
+    }

8-8: Document constructor visibility intention

The constructor has package-private visibility. If this is intentional to restrict instantiation to within the package, consider adding a comment to make this clear.

-    Document(Map<String, String> attributes) {
+    // Package-private constructor to restrict instantiation to within this package
+    Document(Map<String, String> attributes) {
book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java (2)

21-21: Extract "IMAGE" as a constant

The string "IMAGE" is hardcoded in the importFile method. Consider extracting it to a constant for better maintainability.

 package project;

 import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 import static project.Attributes.*;

 public class ImageImporter implements Importer{
+    private static final String IMAGE_TYPE = "IMAGE";
 
     @Override
     public Document importFile(File file) throws IOException {
         final Map<String, String> attributes = new HashMap<>();
         attributes.put(PATH, file.getPath());

         final BufferedImage image = ImageIO.read(file);
         attributes.put(WIDTH, String.valueOf(image.getWidth()));
         attributes.put(HEIGHT, String.valueOf(image.getHeight()));
-        attributes.put(TYPE, "IMAGE");
+        attributes.put(TYPE, IMAGE_TYPE);
         return new Document(attributes);
     }

11-11: Add space after class name and interface name

There should be a space between the class name and the opening curly brace, as well as between implements and Importer.

-public class ImageImporter implements Importer{
+public class ImageImporter implements Importer {
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html (1)

134-135: Consider using HTTPS for external links.

The link to Gradle should use HTTPS instead of HTTP for improved security.

-<a href="http://www.gradle.org">Gradle 8.5</a>
+<a href="https://www.gradle.org">Gradle 8.5</a>
🧰 Tools
🪛 ast-grep (0.38.1)

[warning] 134-134: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html

(plaintext-http-link-html)

book/real-world-software-development/chapter4/document-management/src/main/java/project/InvoiceImporter.java (2)

23-23: Consider using a constant for document type.

For consistency and to avoid magic strings, define a constant for the document type value.

+private static final String INVOICE_TYPE = "INVOICE";

@Override
public Document importFile(final File file) throws IOException {
    // ... existing code
    
    final Map<String, String> attributes = textFile.getAttributes();
-   attributes.put(TYPE, "INVOICE");
+   attributes.put(TYPE, INVOICE_TYPE);
    return new Document(attributes);
}

10-16: Add documentation about expected file format.

Adding a class-level Javadoc comment with information about the expected format of invoice files would improve maintainability.

+/**
+ * Imports invoice documents assuming the following format:
+ * - Contains a line starting with "Dear " followed by the patient name
+ * - Contains a line starting with "Amount: " followed by the invoice amount
+ */
class InvoiceImporter implements Importer {
    private static final String NAME_PREFIX = "Dear ";
    private static final String AMOUNT_PREFIX = "Amount: ";
book/real-world-software-development/chapter4/document-management/src/main/java/project/LetterImporter.java (2)

23-23: Consider using a constant for document type.

For consistency and to avoid magic strings, define a constant for the document type value.

+private static final String LETTER_TYPE = "LETTER";

@Override
public Document importFile(final File file) throws IOException {
    // ... existing code
    
    final Map<String, String> attributes = textFile.getAttributes();
-   attributes.put(TYPE, "LETTER");
+   attributes.put(TYPE, LETTER_TYPE);
    return new Document(attributes);
}

10-14: Add documentation about expected file format.

Adding a class-level Javadoc comment with information about the expected format of letter files would improve maintainability.

+/**
+ * Imports letter documents assuming the following format:
+ * - Contains a line starting with "Dear " followed by the patient name
+ * - Address starts at line 2 and continues until an empty line is found
+ * - Body starts after the address and continues until a line starting with "regards,"
+ */
class LetterImporter implements Importer {
    private static final String NAME_PREFIX = "Dear ";
book/real-world-software-development/chapter4/document-management/src/main/java/project/ReportImporter.java (3)

17-17: Improve readability of the line predicate.

Using line -> false as a predicate is a bit cryptic. Replace it with a more descriptive approach that clarifies the intent.

-textFile.addLines(2, line -> false, BODY);
+// Capture all remaining lines as the body (predicate never returns true)
+textFile.addLines(2, line -> false, BODY);

Alternatively, consider creating a named method:

+private boolean neverStop(String line) {
+    return false; // Continue processing until end of file
+}

@Override
public Document importFile(final File file) throws IOException {
    final TextFile textFile = new TextFile(file);
    textFile.addLineSuffix(NAME_PREFIX, PATIENT);
-   textFile.addLines(2, line -> false, BODY);
+   textFile.addLines(2, this::neverStop, BODY);

20-20: Consider using a constant for document type.

For consistency and to avoid magic strings, define a constant for the document type value.

+private static final String REPORT_TYPE = "REPORT";

@Override
public Document importFile(final File file) throws IOException {
    // ... existing code
    
    final Map<String, String> attributes = textFile.getAttributes();
-   attributes.put(TYPE, "REPORT");
+   attributes.put(TYPE, REPORT_TYPE);
    return new Document(attributes);
}

10-14: Add documentation about expected file format.

Adding a class-level Javadoc comment with information about the expected format of report files would improve maintainability.

+/**
+ * Imports report documents assuming the following format:
+ * - Contains a line starting with "Patient: " followed by the patient name
+ * - All content from line 2 onwards is captured as the body
+ */
class ReportImporter implements Importer {
    private static final String NAME_PREFIX = "Patient: ";
book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java (1)

22-31: Consider case-insensitive matching and trimming whitespace.

The current implementation uses exact string matching with contains(), which might not be user-friendly. Consider adding options for case-insensitive matching and trimming whitespace for more flexible searching.

@Override
public boolean test(final Document document) {
    return clauses.entrySet()
            .stream()
            .allMatch(entry -> {
                final String documentValue = document.getAttribute(entry.getKey());
                final String queryValue = entry.getValue();
-               return documentValue != null && documentValue.contains(queryValue);
+               return documentValue != null && 
+                      documentValue.toLowerCase().contains(queryValue.toLowerCase().trim());
            });
}
book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java (2)

30-48: Optimize memory usage in addLines method.

The method builds a potentially large string in memory using StringBuilder. For very large files, this could cause memory issues. Additionally, there's no validation for the starting index.

int addLines(
        final int start,
        final Predicate<String> isEnd,
        final String attributeName) {

+    // Validate input parameters
+    if (start < 0 || start >= lines.size()) {
+        throw new IllegalArgumentException("Invalid start index: " + start);
+    }
+    if (isEnd == null) {
+        throw new IllegalArgumentException("Predicate cannot be null");
+    }
+    if (attributeName == null || attributeName.isEmpty()) {
+        throw new IllegalArgumentException("Attribute name cannot be null or empty");
+    }

    final StringBuilder accumulator = new StringBuilder();
    int lineNumber;
    for (lineNumber = start; lineNumber < lines.size(); lineNumber++) {
        final String line = lines.get(lineNumber);
        if (isEnd.test(line)) {
            break;
        }

        accumulator.append(line);
        accumulator.append("\n");
    }
    attributes.put(attributeName, accumulator.toString().trim());
    return lineNumber;
}

50-57: Return result of addLineSuffix operation for better caller feedback.

The addLineSuffix method silently fails if it can't find a line starting with the prefix. Consider returning a boolean indicating success or failure, or throw an exception for critical scenarios.

-void addLineSuffix(final String prefix, final String attributeName) {
+boolean addLineSuffix(final String prefix, final String attributeName) {
+    if (prefix == null || attributeName == null) {
+        throw new IllegalArgumentException("Prefix and attribute name cannot be null");
+    }
+    
    for(final String line: lines) {
        if (line.startsWith(prefix)) {
            attributes.put(attributeName, line.substring(prefix.length()));
-            break;
+            return true;
        }
    }
+    return false;
}
book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (3)

11-25: Good class structure with proper encapsulation

The class follows good object-oriented design principles with:

  • Private mutable list with public immutable view (defensive programming)
  • Strategy pattern for importers using a map of file extensions
  • Clear separation of concerns via the Importer interface

Consider consolidating the instance initializer block with the constructor for better readability and maintainability.

 public DocumentManagementSystem() {
     extensionToImporter.put("letter", new LetterImporter());
     extensionToImporter.put("report", new ReportImporter());
     extensionToImporter.put("jpg", new ImageImporter());
+    extensionToImporter.put("invoice", new InvoiceImporter());
 }

-{
-    extensionToImporter.put("invoice", new InvoiceImporter());
-}

27-49: Simplify extension check logic and standardize error messages

The implementation correctly validates files and handles appropriate exceptions. However, there's some redundancy in the extension validation logic, and the error messages aren't consistent.

 public void importFile(final String path) throws IOException {
     final File file = new File(path);
     if (!file.exists()) {
         throw new FileNotFoundException(path);
     }

     final int separatorIndex = path.lastIndexOf('.');
-    if (separatorIndex != -1) {
-        if (separatorIndex == path.length()) {
-            throw new UnknownFileTypeException("No extension found For file: " + path);
-        }
+    if (separatorIndex != -1 && separatorIndex < path.length() - 1) {
         final String extension = path.substring(separatorIndex + 1);
         final Importer importer = extensionToImporter.get(extension);
         if (importer == null) {
-            throw new UnknownFileTypeException("For file: " + path);
+            throw new UnknownFileTypeException("Unknown extension for file: " + path);
         }

         final Document document = importer.importFile(file);
         documents.add(document);
     } else {
         throw new UnknownFileTypeException("No extension found For file: " + path);
     }
 }

51-59: Consider adding Javadoc for public methods

The search method leverages Java 8 streams and the Query class effectively. Add documentation to improve code readability and maintainability.

+/**
+ * Returns an unmodifiable view of all documents in the system.
+ * 
+ * @return List of documents
+ */
 public List<Document> contents() {
     return documentsView;
 }

+/**
+ * Searches for documents matching the specified query string.
+ * The query format is "key:value,key:value" where keys are document attributes.
+ * 
+ * @param query the query string to search for
+ * @return List of matching documents
+ */
 public List<Document> search(final String query) {
     return documents.stream()
             .filter(Query.parse(query))
             .collect(Collectors.toList());
 }
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html (1)

479-480: Use HTTPS links for security

Update the Gradle link to use HTTPS instead of HTTP for better security.

-<a href="http://www.gradle.org">Gradle 8.5</a>
+<a href="https://www.gradle.org">Gradle 8.5</a>
🧰 Tools
🪛 ast-grep (0.38.1)

[warning] 479-479: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html

(plaintext-http-link-html)

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js (2)

1-3: Remove redundant 'use strict' directive

JavaScript modules automatically run in strict mode without needing the directive.

 (function (window, document) {
-    "use strict";
 
     var tabs = {};
🧰 Tools
🪛 Biome (1.9.4)

[error] 2-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)


14-28: Consider using modern DOM manipulation methods

The code works but uses older DOM manipulation approaches. Consider using modern methods like classList instead of directly manipulating class attributes.

 function getClassAttribute(element) {
-    if (element.getAttribute("className")) {
-        return element.getAttribute("className");
-    } else {
-        return element.getAttribute("class");
-    }
+    return element.className;
 }

 function addClass(element, classValue) {
-    changeElementClass(element, getClassAttribute(element) + " " + classValue);
+    element.classList.add(classValue);
 }

 function removeClass(element, classValue) {
-    changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
+    element.classList.remove(classValue);
 }
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (1)

1-1: Fix package name typo.

The package name chpater4 contains a typo and should be chapter4 instead.

-package chpater4;
+package chapter4;
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/base-style.css (2)

104-105: Remove empty CSS rule.

The CSS rule for div.tab is empty and doesn't serve any purpose. Consider removing it or adding the necessary styles.

-div.tab {
-}
🧰 Tools
🪛 Biome (1.9.4)

[error] 104-105: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


1-179: Consider excluding auto-generated CSS files from version control.

This appears to be an auto-generated CSS file from test reports. Consider whether it's necessary to include this in version control, as these files are typically regenerated when tests are run. You might want to add build output directories to your .gitignore file.

Would you like me to propose a suitable .gitignore configuration for excluding build outputs?

🧰 Tools
🪛 Biome (1.9.4)

[error] 104-105: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between d05215e and 611b3d5.

⛔ Files ignored due to path filters (17)
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Attributes.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Document.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/DocumentManagementSystem.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/ImageImporter.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Importer.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/InvoiceImporter.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/LetterImporter.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Query.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/ReportImporter.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/TextFile.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/UnknownFileTypeException.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/classes/java/test/chpater4/DocumentManagementSystemTest.class is excluded by !**/*.class
  • book/real-world-software-development/chapter4/document-management/build/test-results/test/binary/output.bin is excluded by !**/*.bin
  • book/real-world-software-development/chapter4/document-management/build/test-results/test/binary/results.bin is excluded by !**/*.bin
  • book/real-world-software-development/chapter4/document-management/build/tmp/compileJava/previous-compilation-data.bin is excluded by !**/*.bin
  • book/real-world-software-development/chapter4/document-management/build/tmp/compileTestJava/previous-compilation-data.bin is excluded by !**/*.bin
  • book/real-world-software-development/chapter4/document-management/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
📒 Files selected for processing (37)
  • book/real-world-software-development/chapter4/README.md (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build.gradle.kts (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/base-style.css (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/style.css (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/reports/tests/test/index.html (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html (1 hunks)
  • book/real-world-software-development/chapter4/document-management/build/test-results/test/TEST-chpater4.DocumentManagementSystemTest.xml (1 hunks)
  • book/real-world-software-development/chapter4/document-management/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • book/real-world-software-development/chapter4/document-management/gradlew (1 hunks)
  • book/real-world-software-development/chapter4/document-management/gradlew.bat (1 hunks)
  • book/real-world-software-development/chapter4/document-management/settings.gradle.kts (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/Importer.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/InvoiceImporter.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/LetterImporter.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/ReportImporter.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java (1 hunks)
  • book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (1 hunks)
  • javav-network/src/main/java/project/reflect/caculator/Calculator.java (1 hunks)
  • javav-network/src/main/java/project/was/httpserver/HttpRequest.java (1 hunks)
  • javav-network/src/main/java/project/was/httpserver/HttpResponse.java (1 hunks)
  • javav-network/src/main/java/project/was/httpserver/HttpServlet.java (1 hunks)
  • javav-network/src/main/java/project/was/httpserver/ServletManager.java (1 hunks)
  • javav-network/src/main/java/project/was/httpserver/servlet/NotFoundServlet.java (1 hunks)
  • javav-network/src/main/java/project/was/v3/PercentEncodingMain.java (1 hunks)
  • javav-network/src/main/java/project/was/v5/servlet/HttpServlet.java (1 hunks)
  • simple-java/docs/chapter4.md (1 hunks)
  • thread-pool-optimization/k6/io_user_test.js (1 hunks)
  • thread-pool-optimization/src/main/java/project/threadpooloptimization/interfaces/UserController.java (1 hunks)
  • thread-pool-optimization/src/main/resources/application.yml (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
javav-network/src/main/java/project/was/httpserver/HttpServlet.java (1)
javav-network/src/main/java/project/was/v5/servlet/HttpServlet.java (1)
  • HttpServlet (3-4)
book/real-world-software-development/chapter4/document-management/src/main/java/project/ReportImporter.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
  • Attributes (4-14)
book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
  • Attributes (4-14)
book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java (1)
  • Query (9-32)
book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
  • Attributes (4-14)
book/real-world-software-development/chapter4/document-management/src/main/java/project/InvoiceImporter.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
  • Attributes (4-14)
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (4)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java (1)
  • Document (5-16)
book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (1)
  • DocumentManagementSystem (11-60)
book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java (1)
  • UnknownFileTypeException (3-7)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
  • Attributes (4-14)
🪛 ast-grep (0.38.1)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html

[warning] 134-134: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html

(plaintext-http-link-html)

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/index.html

[warning] 164-164: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html

(plaintext-http-link-html)

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html

[warning] 479-479: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html

(plaintext-http-link-html)

🪛 Biome (1.9.4)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/base-style.css

[error] 104-105: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js

[error] 2-2: Redundant use strict directive.

The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.

(lint/suspicious/noRedundantUseStrict)

🔇 Additional comments (21)
javav-network/src/main/java/project/was/v3/PercentEncodingMain.java (1)

9-13: Encoding and decoding logic is correct.
The use of URLEncoder.encode and URLDecoder.decode with StandardCharsets.UTF_8 correctly demonstrates percent-encoding/decoding in UTF-8.

javav-network/src/main/java/project/was/httpserver/ServletManager.java (1)

6-9: Good use of proper encapsulation for servlet registry.

The ServletManager class correctly uses a private final Map for storing servlet mappings, which prevents external modification of the collection reference and enforces access control through the provided methods.

book/real-world-software-development/chapter4/document-management/settings.gradle.kts (1)

1-2: LGTM!

The settings file correctly sets the root project name to "document-management". This follows standard Gradle project configuration practices.

book/real-world-software-development/chapter4/document-management/src/main/java/project/Importer.java (1)

6-8: LGTM! Good interface design.

The Importer interface is well-designed with a single, clear responsibility. It follows the Single Responsibility Principle by focusing only on importing documents from files. The method signature properly declares the checked IOException that implementations might throw.

book/real-world-software-development/chapter4/document-management/build.gradle.kts (1)

12-21: LGTM! Dependencies are well-organized.

Good job organizing the test dependencies with clear comments for each group. Including both JUnit 5 and Hamcrest provides a comprehensive testing toolkit.

book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java (1)

3-7: LGTM! Well-designed exception class.

The exception class follows good practices:

  • Descriptive name that clearly communicates its purpose
  • Extends the appropriate base class (RuntimeException)
  • Provides a constructor that passes the message to the parent class

This unchecked exception is appropriate for signaling programming errors like attempting to import an unsupported file type.

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/style.css (1)

1-85: Auto-generated file - no review needed

This CSS file is auto-generated by Gradle's test reporting mechanism and not intended for manual editing. It follows standard CSS practices for styling test report elements.

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html (1)

31-32: Note the high test failure rate.

7 out of 8 tests are failing, suggesting significant issues with the implementation or test expectations. This might be expected for an educational project, but should be addressed before considering the code complete.

book/real-world-software-development/chapter4/document-management/build/reports/tests/test/index.html (1)

1-169: Test failures indicate missing test resource files.

The test report shows 7 failed tests out of 8, with a 12% success rate. Most failures appear to be due to missing test resource files in the src/test/resources directory.

Create the required test resource files in the appropriate directory to make the tests pass.

🧰 Tools
🪛 ast-grep (0.38.1)

[warning] 164-164: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html

(plaintext-http-link-html)

book/real-world-software-development/chapter4/document-management/gradlew.bat (1)

1-89: Standard Gradle wrapper script with proper setup

This is a standard Gradle wrapper batch script for Windows, which follows best practices for Gradle project setup.

book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (4)

59-63: Good use of test data and assertion methods.

The test properly verifies multiple attributes of the letter document, ensuring that the LetterImporter correctly extracts all required information. This aligns with the strong typing principle mentioned in the PR objectives.


101-111: Well-implemented search functionality test.

This test effectively demonstrates searching for documents by multiple attributes (patient name and body content), verifying the Query parsing and filtering functionality. Good example of the practical implementation of the domain classes concept mentioned in the README.


114-125: Good error handling test cases.

These tests verify appropriate exception handling for missing files and unknown file types, which is important for robust error management. This follows good testing practices by ensuring failure cases are handled properly.


137-148: Well-structured helper method for assertions.

The assertAttributeEquals method provides clear error messages and reduces code duplication, making the tests more maintainable. This demonstrates good test hygiene as mentioned in the PR objectives.

book/real-world-software-development/chapter4/README.md (6)

1-13: Clear requirement specification.

The requirements section effectively outlines the core functionality needed for the document management system: reading existing patient files, adding indexing, and enabling search across different document types (reports, mail, images). It also specifies the need for extensibility, which aligns with the composition over inheritance principle mentioned in the PR objectives.


18-20: Good explanation of switch statement limitations.

This section correctly identifies the extensibility problem with switch statements, which is a practical example of why composition is preferred over procedural approaches. This directly relates to the composition over inheritance principle mentioned in the PR objectives.


21-24: Well-articulated strong typing principles.

The explanation of strong typing principles and immutable objects aligns with the PR objectives. It correctly highlights how these principles help localize errors and enable safe indexing and caching of documents.


32-35: Good explanation of ubiquitous language.

This section effectively explains the concept of ubiquitous language and how it improves communication between developers and customers by using consistent terminology. This directly supports the PR objective regarding ubiquitous language.


40-48: Comprehensive explanation of Liskov Substitution Principle.

The detailed explanation of LSP with its four main rules provides a clear understanding of proper inheritance and interface implementation. This aligns with the PR objectives about LSP and provides valuable guidelines for the implementation.


52-66: Thorough discussion of code reuse methods.

This section effectively covers the three ways to reuse code mentioned in the PR objectives (utility classes, inheritance, and domain classes), including the pros and cons of each approach. The warning about improper inheritance is particularly valuable.

book/real-world-software-development/chapter4/document-management/gradlew (1)

1-234:

Details

✅ Verification successful

Ensure Gradle wrapper has executable permissions.

This is a standard Gradle wrapper script. Make sure it has executable permissions so it can be run directly.


🏁 Script executed:

#!/bin/bash
# Check if the gradlew file has executable permissions
ls -la gradlew
echo "Setting executable permissions"
chmod +x gradlew
ls -la gradlew

Length of output: 291


Let’s locate the wrapper script in its actual path and verify its permissions:


🏁 Script executed:

#!/bin/bash
# Locate the gradlew file anywhere in the repo
wrapper=$(find . -type f -name gradlew | head -n1)
if [ -z "$wrapper" ]; then
  echo "ERROR: gradlew not found in repository"
  exit 1
fi

echo "Found wrapper at: $wrapper"
ls -la "$wrapper"

echo "Ensuring executable permissions…"
chmod +x "$wrapper"
ls -la "$wrapper"

Length of output: 556


Verified: Gradle wrapper is already executable

The gradlew script located at java-syncronized/gradlew has -rwxr-xr-x permissions, so no further action is needed.

Comment on lines +1 to +2
package project.reflect.caculator;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Typo in package name.

The package declaration project.reflect.caculator (and corresponding directory caculator) is misspelled. This will lead to inconsistent imports and runtime reflection errors. Please correct both the package and directory name to calculator:

- package project.reflect.caculator;
+ package project.reflect.calculator;

Rename the folder caculatorcalculator to keep the filesystem in sync with the package.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
package project.reflect.caculator;
package project.reflect.calculator;
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/reflect/caculator/Calculator.java at
lines 1 to 2, the package name is misspelled as "caculator". Rename the package
declaration to "project.reflect.calculator" and also rename the directory from
"caculator" to "calculator" to ensure consistency between the package name and
the filesystem structure.

Comment on lines +1 to +4
package project.was.httpserver;

public interface HttpServlet {
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Define the core servlet contract
The HttpServlet interface is empty, making it unusable as a servlet contract. At minimum, declare a service method that accepts HttpRequest and HttpResponse.

Apply a diff such as:

 package project.was.httpserver;
+
+import project.was.httpserver.HttpRequest;
+import project.was.httpserver.HttpResponse;
 public interface HttpServlet {
-}
+    /**
+     * Process an incoming HTTP request and populate the response.
+     */
+    void service(HttpRequest request, HttpResponse response);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
package project.was.httpserver;
public interface HttpServlet {
}
package project.was.httpserver;
import project.was.httpserver.HttpRequest;
import project.was.httpserver.HttpResponse;
public interface HttpServlet {
/**
* Process an incoming HTTP request and populate the response.
*/
void service(HttpRequest request, HttpResponse response);
}
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/httpserver/HttpServlet.java lines 1
to 4, the HttpServlet interface is currently empty and lacks a core contract.
Define a service method in the interface that takes HttpRequest and HttpResponse
parameters to establish the basic servlet contract. This will make the interface
usable for handling HTTP requests and responses.

Comment on lines +1 to +4
package project.was.v5.servlet;

public class HttpServlet {
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid duplicate HttpServlet definitions
There are two HttpServlet types in the codebase (httpserver.HttpServlet and v5.servlet.HttpServlet), which will cause confusion and complicate maintenance. Consider removing or renaming the versioned class, or have it implement/extend the core HttpServlet interface introduced above.

🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/v5/servlet/HttpServlet.java lines 1
to 4, there is a duplicate HttpServlet class conflicting with
httpserver.HttpServlet. To fix this, either remove this versioned HttpServlet
class if it is redundant, rename it to a more specific name to avoid confusion,
or refactor it to extend or implement the core HttpServlet interface from
httpserver to maintain clear hierarchy and reduce duplication.

Comment on lines +1 to +4
package project.was.httpserver;

public class HttpResponse {
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance HttpResponse with response API
HttpResponse is an empty placeholder. To support real-world use, define status code, headers, and body manipulation methods.

Example diff:

 package project.was.httpserver;
+
+import java.io.OutputStream;
+import java.util.Map;
+
 public class HttpResponse {
-}
+    private int statusCode;
+    private Map<String, String> headers;
+    private OutputStream body;
+
+    public void setStatus(int code) { this.statusCode = code; }
+    public int getStatus() { return statusCode; }
+
+    public void addHeader(String name, String value) { headers.put(name, value); }
+    public Map<String, String> getHeaders() { return headers; }
+
+    public OutputStream getBody() { return body; }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
package project.was.httpserver;
public class HttpResponse {
}
package project.was.httpserver;
import java.io.OutputStream;
import java.util.Map;
public class HttpResponse {
private int statusCode;
private Map<String, String> headers;
private OutputStream body;
public void setStatus(int code) { this.statusCode = code; }
public int getStatus() { return statusCode; }
public void addHeader(String name, String value) { headers.put(name, value); }
public Map<String, String> getHeaders() { return headers; }
public OutputStream getBody() { return body; }
}
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/httpserver/HttpResponse.java at lines
1 to 4, the HttpResponse class is currently empty and lacks functionality. Add
fields to store the HTTP status code, headers (using a suitable map structure),
and the response body. Implement methods to set and get the status code, add and
retrieve headers, and set and get the response body content. This will provide a
basic but functional HTTP response API.

Comment on lines +1 to +4
package project.was.httpserver;

public class HttpRequest {
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance HttpRequest with request API
HttpRequest is currently empty. It should expose HTTP method, URI, headers, parameters, and input stream for a usable API.

Example diff:

 package project.was.httpserver;
+
+import java.io.InputStream;
+import java.util.Map;
+
 public class HttpRequest {
-}
+    private String method;
+    private String path;
+    private Map<String, String> headers;
+    private InputStream body;
+
+    public String getMethod() { return method; }
+    public String getPath() { return path; }
+
+    public String getHeader(String name) { return headers.get(name); }
+    public InputStream getBody() { return body; }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
package project.was.httpserver;
public class HttpRequest {
}
package project.was.httpserver;
import java.io.InputStream;
import java.util.Map;
public class HttpRequest {
private String method;
private String path;
private Map<String, String> headers;
private InputStream body;
public String getMethod() {
return method;
}
public String getPath() {
return path;
}
public String getHeader(String name) {
return headers.get(name);
}
public InputStream getBody() {
return body;
}
}
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/httpserver/HttpRequest.java at lines
1 to 4, the HttpRequest class is currently empty and lacks functionality.
Implement fields and methods to expose the HTTP method, URI, headers,
parameters, and input stream. This includes adding private variables for these
components and providing public getter methods to access them, enabling the
class to represent and handle HTTP request data properly.

Comment on lines +5 to +47
<failure message="java.io.FileNotFoundException: src/test/resources/patient.report" type="java.io.FileNotFoundException">java.io.FileNotFoundException: src/test/resources/patient.report
at project.DocumentManagementSystem.importFile(DocumentManagementSystem.java:30)
at chpater4.DocumentManagementSystemTest.shouldImportReportAttributes(DocumentManagementSystemTest.java:69)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
</failure>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Create missing test resources to resolve FileNotFoundException errors.

All but one test are failing due to missing resource files. These files need to be created in the src/test/resources directory:

  1. patient.report
  2. patient.invoice
  3. patient.letter
  4. xray.jpg
  5. unknown.txt

Also applies to: 50-92, 95-137, 140-186, 190-232, 235-277, 280-322


🏁 Script executed:

#!/bin/bash
# Check if the test resources directory exists and create it if not
mkdir -p book/real-world-software-development/chapter4/document-management/src/test/resources

# Check which test files are missing
echo "Missing test resource files:"
for file in "patient.report" "patient.invoice" "patient.letter" "xray.jpg" "unknown.txt"; do
  if [ ! -f "book/real-world-software-development/chapter4/document-management/src/test/resources/$file" ]; then
    echo "- $file"
  fi
done

Length of output: 1393


Add missing test resource files to src/test/resources

Several tests are failing with FileNotFoundException because the following resource files are not present under
book/real-world-software-development/chapter4/document-management/src/test/resources:

  • patient.report
  • patient.invoice
  • patient.letter
  • xray.jpg
  • unknown.txt

Please add these files (they can be empty or contain sample data) to the above directory so that the import tests in DocumentManagementSystemTest pass.

🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/src/test/resources
around lines 5 to 47 of the test result XML, the tests fail due to missing
resource files causing FileNotFoundException. To fix this, create the missing
test resource files named patient.report, patient.invoice, patient.letter,
xray.jpg, and unknown.txt in the src/test/resources directory of the
document-management module. These files can be empty or contain sample data to
allow the import tests in DocumentManagementSystemTest to run successfully.

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Class chpater4.DocumentManagementSystemTest</title>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in package name

There's a typo in the package name: "chpater4" should be "chapter4".

This issue affects both the package name in your test code and the corresponding folder structure. You'll need to rename the package and update any references.

🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html
at line 6, correct the typo in the package name from "chpater4" to "chapter4".
Rename the package declaration in the test code accordingly and update the
folder structure to match the corrected package name. Also, ensure all
references to this package in the project are updated to use "chapter4".

Comment on lines +76 to +118
<pre>java.io.FileNotFoundException: src/test/resources/patient.letter
at project.DocumentManagementSystem.importFile(DocumentManagementSystem.java:30)
at chpater4.DocumentManagementSystemTest.shouldBeAbleToSearchFilesByAttributes(DocumentManagementSystemTest.java:103)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
</pre>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Test failures indicate missing test resource files

All tests are failing with FileNotFoundException because the test resource files are missing from the expected location src/test/resources/. Create these files or update the test path references.

Also applies to: 125-167, 174-216, 223-265, 272-314, 321-363, 370-417


🏁 Script executed:

#!/bin/bash
# Check for the existence of test resources directory and files
echo "Checking test resources directory structure..."
ls -la book/real-world-software-development/chapter4/document-management/src/test/resources/ 2>/dev/null || echo "Test resources directory doesn't exist"

# Check if the test is looking for absolute or relative paths
echo "Checking how paths are referenced in the test class..."
grep -A 2 "importFile" book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java 2>/dev/null || echo "Test file not found"

Length of output: 1321


Missing Test Resource Files – Add or Correct src/test/resources

All importFile(...) calls in DocumentManagementSystemTest are failing because the test resources directory and files don’t exist. Please either add the expected files under:

  • book/real-world-software-development/chapter4/document-management/src/test/resources/

or update the test constants/paths in:

  • book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java

Test constants to provide resources for include (but may not be limited to):

  • LETTERpatient.letter
  • REPORTpatient.report
  • XRAYpatient.xray
  • INVOICEpatient.invoice
  • any error tests ("gobbledygook.txt", RESOURCES + "unknown.txt")

Ensure each referenced file exists at the path the test uses (relative to src/test/resources/), or adjust the test to point to your actual resource locations.

🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java
around lines 76 to 118, the tests fail due to missing test resource files like
patient.letter in src/test/resources/. Fix this by either adding the required
files (patient.letter, patient.report, patient.xray, patient.invoice, etc.) to
book/real-world-software-development/chapter4/document-management/src/test/resources/
or by updating the file path constants in the test class to point to the correct
existing resource locations, ensuring all importFile calls reference valid
files.

var spans = document.getElementById("tabs").getElementsByTagName("span");
var codeBlocks = [];
for (var i = 0; i < spans.length; ++i) {
if (spans[i].className.indexOf("code") >= 0) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use more reliable DOM class checking

Using indexOf to check for class names can lead to false positives. For example, if an element has the class "mycode", it would incorrectly match when checking for "code".

-            if (spans[i].className.indexOf("code") >= 0) {
+            if (spans[i].classList.contains("code")) {
                 codeBlocks.push(spans[i]);
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (spans[i].className.indexOf("code") >= 0) {
if (spans[i].classList.contains("code")) {
codeBlocks.push(spans[i]);
}
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js
at line 55, replace the use of indexOf to check for the "code" class with a more
reliable method such as using the classList API's contains method. This ensures
only elements with the exact "code" class are matched, avoiding false positives
from partial matches like "mycode".

Comment on lines +21 to +26
private static final String RESOURCES =
"src" + File.separator + "test" + File.separator + "resources" + File.separator;
private static final String LETTER = RESOURCES + "patient.letter";
private static final String REPORT = RESOURCES + "patient.report";
private static final String XRAY = RESOURCES + "xray.jpg";
private static final String INVOICE = RESOURCES + "patient.invoice";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure test resource files exist.

The tests reference resource files at the specified path that will be required for the tests to run successfully. Make sure these files (patient.letter, patient.report, xray.jpg, and patient.invoice) exist in the test resources directory.


🏁 Script executed:

#!/bin/bash
# Check if the required test resource files exist
echo "Checking for test resource files..."
ls -la src/test/resources/ || echo "Resources directory not found"

Length of output: 245


Missing test resource files directory

The directory src/test/resources/ is not present, so the tests won’t be able to locate the resource files. Please:

  • Create the src/test/resources/ directory.
  • Add the following files to that directory:
    • patient.letter
    • patient.report
    • xray.jpg
    • patient.invoice
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java
around lines 21 to 26, the test resource files referenced do not exist because
the directory src/test/resources/ is missing. To fix this, create the directory
src/test/resources/ in the project structure and add the required files
patient.letter, patient.report, xray.jpg, and patient.invoice to that directory
so the tests can access them properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants