diff --git a/AGENTS.md b/AGENTS.md index 89d81ab9..9c5e4a59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,33 +10,47 @@ LLM-based agents can accelerate development only if they respect our house rules | Requirement | Rationale | |--------------|-----------| -| **British English** spelling (`organisation`, `licence`, *not* `organization`, `license`) except technical US spellings like `synchronized` | Keeps wording consistent with Chronicle's London HQ and existing docs. See the University of Oxford style guide for reference. | -| **ASCII-7 only** (code-points 0-127). Avoid smart quotes, non-breaking spaces and accented characters. | ASCII-7 survives every toolchain Chronicle uses, incl. low-latency binary wire formats that expect the 8th bit to be 0. | -| If you must show a symbol that does not exist in ASCII-7, spell it out (`micro-second`, `>=`, `:alpha:`, `:yes:`) rather than inserting Unicode. | Extended or '8-bit ASCII' variants are *not* portable and are therefore disallowed. | +| **British English** spelling (`organisation`, `licence`, *not* `organization`, `license`) except technical US spellings like `synchronized` | Keeps wording consistent with Chronicle's London HQ and existing docs. See the [University of Oxford style guide](https://www.ox.ac.uk/public-affairs/style-guide) for reference. | +| **ISO-8859-1** (code-points 0-255). Avoid smart quotes, non-breaking spaces and accented characters. | ISO-8859-1 survives every toolchain Chronicle uses. | +| If a symbol is not available in ISO-8859-1, use a textual form such as `>=`, `:alpha:`, `:yes:`. This is the preferred approach and Unicode must not be inserted. | Extended or '8-bit ASCII' variants are *not* portable and are therefore disallowed. | +| Tools to check ASCII compliance include `iconv -f ascii -t ascii` and IDE settings that flag non-ASCII characters. | These help catch stray Unicode characters before code review. | ## Javadoc guidelines **Goal:** Every Javadoc block should add information you cannot glean from the method signature alone. Anything else is noise and slows readers down. -| Do | Don’t | +| Do | Don't | |----|-------| | State *behavioural contracts*, edge-cases, thread-safety guarantees, units, performance characteristics and checked exceptions. | Restate the obvious ("Gets the value", "Sets the name"). | | Keep the first sentence short; it becomes the summary line in aggregated docs. | Duplicate parameter names/ types unless more explanation is needed. | -| Prefer `@param` for *constraints* and `@throws` for *conditions*, following Oracle’s style guide. | Pad comments to reach a line-length target. | +| Prefer `@param` for *constraints* and `@throws` for *conditions*, following Oracle's style guide. | Pad comments to reach a line-length target. | | Remove or rewrite autogenerated Javadoc for trivial getters/setters. | Leave stale comments that now contradict the code. | -The principle that Javadoc should only explain what is *not* manifest from the signature is well-established in the -wider Java community. +The principle that Javadoc should only explain what is *not* manifest from the +signature is well-established in the wider Java community. + +Inline comments should also avoid noise. The following example shows the +difference: + +```java +// BAD: adds no value +int count; // the count + +// GOOD: explains a subtlety +// count of messages pending flush +int count; +``` ## Build & test commands -Agents must verify that the project still compiles and all unit tests pass before opening a PR: +Agents must verify that the project still compiles and all unit tests pass before opening a PR. Running from a clean checkout avoids stale artifacts: ```bash # From repo root -mvn -q verify +mvn -q clean verify ``` +The command should exit with code `0` to indicate success. ## Commit-message & PR etiquette @@ -45,15 +59,33 @@ mvn -q verify 3. In *body*: *root cause -> fix -> measurable impact* (latency, allocation, etc.). Use ASCII bullet points. 4. **Run `mvn verify`** again after rebasing. +### When to open a PR + +* Open a pull request once your branch builds and tests pass with `mvn -q clean verify`. +* Link the PR to the relevant issue or decision record. +* Keep PRs focused: avoid bundling unrelated refactoring with new features. +* Re-run the build after addressing review comments to ensure nothing broke. + ## What to ask the reviewers * *Is this AsciiDoc documentation precise enough for a clean-room re-implementation?* * Does the Javadoc explain the code's *why* and *how* that a junior developer would not be expected to work out? +* Are the documentation, tests and code updated together so the change is clear? +* Does the commit point back to the relevant requirement or decision tag? +* Would an example or small diagram help future maintainers? + +### Security checklist (review **after every change**) + +**Run a security review on *every* PR**: Walk through the diff looking for input validation, authentication, authorisation, encoding/escaping, overflow, resource exhaustion and timing-attack issues. + +**Never commit secrets or credentials**: tokens, passwords, private keys, TLS materials, internal hostnames, Use environment variables, HashiCorp Vault, AWS/GCP Secret Manager, etc. + +**Document security trade-offs**: Chronicle prioritises low-latency systems; sometimes we relax safety checks for specific reasons. Future maintainers must find these hot-spots quickly, In Javadoc and `.adoc` files call out *why* e.g. "Unchecked cast for performance - assumes trusted input". ## Project requirements -See the [Decision Log](src/main/adoc/decision-log.adoc) for the latest project decisions. -See the [Project Requirements](src/main/adoc/project-requirements.adoc) for details on project requirements. +See the [Decision Log](src/main/docs/decision-log.adoc) for the latest project decisions. +See the [Project Requirements](src/main/docs/project-requirements.adoc) for details on project requirements. ## Elevating the Workflow with Real-Time Documentation @@ -61,18 +93,14 @@ Building upon our existing Iterative Workflow, the newest recommendation is to e Ensure the relevant `.adoc` files are updated when features, requirements, implementation details, or tests change. This tight loop informs the AI accurately and creates immediate clarity for all team members. -### Benefits +### Benefits of Real-Time Documentation -* **Confidence in Documentation**: Accurate docs prevent "miscommunications" that derail real-world outcomes. -* **Better Onboarding**: An up-to-date AsciiDoc set means new developers grasp the system's design and requirements more quickly. -* **Incremental Changes**: Thanks to the incremental mode, AIDE flags any newly updated files so you can keep the documentation synchronised. - -### Benefits of Keeping Requirements, Tests, and Code In Sync - -* **Reduced Drift**: Minimises gaps between documentation, tested behaviour, and implementation. -* **Faster Feedback**: AI can quickly generate stubs based on docs/tests and highlight inconsistencies discovered during analysis. -* **Better Quality**: Frequent checks align the code with specified requirements and verifiable tests. -* **Smoother Onboarding**: Up-to-date AsciiDoc clarifies the system for new developers or team members switching contexts. +* **Confidence in documentation**: Accurate docs prevent miscommunications that derail real-world outcomes. +* **Reduced drift**: Real-time updates keep requirements, tests and code aligned. +* **Faster feedback**: AI can quickly highlight inconsistencies when everything is in sync. +* **Better quality**: Frequent checks align the implementation with the specified behaviour. +* **Smoother onboarding**: Up-to-date AsciiDoc clarifies the system for new developers. +* **Incremental changes**: AIDE flags newly updated files so you can keep the documentation synchronised. ### Best Practices @@ -85,8 +113,8 @@ This tight loop informs the AI accurately and creates immediate clarity for all When using AI agents to assist with development, please adhere to the following guidelines: -* **Respect the Language & Character-set Policy**: Ensure all AI-generated content follows the British English and ASCII-7 guidelines outlined above. - Focus on Clarity: AI-generated documentation should be clear and concise and add value beyond what is already present in the code or existing documentation. +* **Respect the Language & Character-set Policy**: Ensure all AI-generated content follows the British English and ISO-8859-1 guidelines outlined above. +Focus on Clarity: AI-generated documentation should be clear and concise and add value beyond what is already present in the code or existing documentation. * **Avoid Redundancy**: Do not generate content that duplicates existing documentation or code comments unless it provides additional context or clarification. * **Review AI Outputs**: Always review AI-generated content for accuracy, relevance, and adherence to the project's documentation standards before committing it to the repository. @@ -119,13 +147,12 @@ To improve traceability, we adopt the Nine-Box taxonomy for requirement and deci ```asciidoc === [Identifier] Title of Decision -- Date: YYYY-MM-DD -- Context: +Date :: YYYY-MM-DD +Context :: * What is the issue that this decision addresses? * What are the driving forces, constraints, and requirements? -- Decision Statement: -* What is the change that is being proposed or was decided? -- **Alternatives Considered:** +Decision Statement :: What is the change that is being proposed or was decided? +Alternatives Considered :: * [Alternative 1 Name/Type]: ** *Description:* Brief description of the alternative. ** *Pros:* ... @@ -134,14 +161,14 @@ To improve traceability, we adopt the Nine-Box taxonomy for requirement and deci ** *Description:* Brief description of the alternative. ** *Pros:* ... ** *Cons:* ... -- **Rationale for Decision:** +Rationale for Decision :: * Why was the chosen decision selected? * How does it address the context and outweigh the cons of alternatives? -- **Impact & Consequences:** +Impact & Consequences :: * What are the positive and negative consequences of this decision? * How does this decision affect the system, developers, users, or operations? - What are the trade-offs made? -- **Notes/Links:** +Notes/Links :: ** (Optional: Links to relevant issues, discussions, documentation, proof-of-concepts) ``` @@ -152,11 +179,31 @@ To improve traceability, we adopt the Nine-Box taxonomy for requirement and deci Do not rely on indentation for list items in AsciiDoc documents. Use the following pattern instead: ```asciidoc -- top level -* second level - ** third level +section :: Top Level Section (Optional) +* first level + ** nested level ``` ### Emphasis and Bold Text -In AsciiDoc, an underscore `_` is _emphasis_; `*text*` is *bold*. \ No newline at end of file +In AsciiDoc, an underscore `_` is _emphasis_; `*text*` is *bold*. + +### Section Numbering + +Use automatic section numbering for all `.adoc` files. + +* Add `:sectnums:` to the document header. +* Do not prefix section titles with manual numbers to avoid duplication. + +```asciidoc += Document Title +Chronicle Software +:toc: +:sectnums: +:lang: en-GB +:source-highlighter: rouge + +The document overview goes here. + +== Section 1 Title +``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..9bf30cfb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,173 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Chronicle Test Framework (CTF) is a Java library providing test-data generators and API metrics tools for JUnit 4 and JUnit 5. It specialises in exhaustive test case generation through combinatorial utilities and provides OpenHFT-specific testing support. + +**Key capabilities:** +- Combinatorial test data generation: `Permutation.of()`, `Combination.of()`, `Product.of()`, `Series.of()` +- API metrics analysis for measuring public/internal API surface +- Testing utilities for concurrency, resources, network, and processes +- DTO testing utilities +- Flaky test handling and exception tracking + +## Build Commands + +```bash +# Full build and test (REQUIRED before opening PRs) +mvn -q verify + +# Run tests only +mvn -q test + +# Run a single test class +mvn -q test -Dtest=ClassName + +# Run a single test method +mvn -q test -Dtest=ClassName#methodName + +# Clean build +mvn clean install + +# Skip tests (use sparingly) +mvn -q install -DskipTests +``` + +**Important:** The surefire plugin uses `forkCount=4` and `reuseForks=true`, giving each test class its own JVM. System properties can be safely set per test class but not per method. + +## Code Architecture + +### Package Structure + +**Main packages:** +- `net.openhft.chronicle.testframework` - Core utilities and combinatorial generators +- `net.openhft.chronicle.testframework.apimetrics` - API metrics analysis (Metric, Accumulator, ApiMetrics) +- `net.openhft.chronicle.testframework.dto` - DTO testing utilities +- `net.openhft.chronicle.testframework.exception` - Exception tracking utilities +- `net.openhft.chronicle.testframework.function` - Functional interfaces (NamedConsumer, ThrowingConsumer, TriConsumer) +- `net.openhft.chronicle.testframework.process` - Java process management for multi-process tests +- `net.openhft.chronicle.testframework.mappedfiles` - Memory-mapped file utilities +- `net.openhft.chronicle.testframework.internal.*` - Implementation classes (not for external use) + +**Internal convention:** Packages with `.internal.` in the name or ending in `.internal` contain implementation classes. Non-internal classes must not extend internal classes (enforced by CodeStructureVerifier). + +### Combinatorial Test Generation + +The framework's core strength is exhaustive test data generation using: + +1. **Permutation** - All orderings of elements (factorial growth) +2. **Combination** - All subsets of elements (power set) +3. **Product** - Cartesian product (nested loop equivalent) +4. **Series** - Numeric sequences for parameterised tests + +These integrate with JUnit 5's `@TestFactory` and `DynamicTest.stream()` for declarative exhaustive testing. + +### API Metrics Architecture + +The API metrics system uses a builder pattern: +1. **Metric** - Defines what to measure (e.g., public methods, deprecated APIs) +2. **Accumulator** - Defines how to group results (e.g., per class, per package) +3. **ApiMetrics** - Container for aggregated results, separates public/internal packages + +Builder workflow: `ApiMetrics.builder()` → add packages → add metrics → add accumulators → `build()` + +Packages are classified as internal if they contain `.internal.` or end with `.internal`. + +### Delegation Pattern + +The framework uses a delegation builder (`Delegation.builder()`) to create delegator instances that forward method calls to delegate objects. This is used internally for creating proxy implementations. + +## Language and Character Set + +**CRITICAL:** Follow Chronicle Software's house rules from AGENTS.md: + +- Use **British English** spelling (`organisation`, `licence`) except technical US terms (`synchronized`) +- **ASCII-7 only** (code-points 0-127) - no Unicode, smart quotes, or accented characters +- Spell out symbols: `micro-second`, `>=`, not Unicode equivalents + +## Javadoc Guidelines + +**Write Javadoc that adds information beyond the method signature:** + +**Do:** +- State behavioural contracts, edge cases, thread-safety guarantees, units, performance characteristics +- Keep first sentence short (becomes summary line) +- Use `@param` for constraints, `@throws` for conditions +- Remove/rewrite autogenerated Javadoc for trivial getters/setters + +**Don't:** +- Restate the obvious ("Gets the value", "Sets the name") +- Duplicate parameter names/types unless adding explanation +- Leave stale comments that contradict code +- Pad comments to reach line-length targets + +## Testing Patterns + +### Dynamic Test Generation + +Prefer this pattern for exhaustive testing: + +```java +@TestFactory +Stream exhaustiveTest() { + return DynamicTest.stream( + Permutation.of(operation1, operation2, operation3), + Objects::toString, + operations -> { + // Test logic using operations + } + ); +} +``` + +### Main Method Requirements + +Any class with a `main` method must include a static initializer calling `net.openhft.chronicle.core.Bootstrap.bootstrap()` (enforced by CodeStructureVerifier). + +### DTO Testing + +Use `DtoTester.builder()` to test data transfer objects for proper equals/hashCode/toString implementation. + +## Project Requirements + +**Reference documents:** +- `src/main/adoc/project-requirements.adoc` - Comprehensive requirements for AI-driven enhancements +- Decision log referenced in requirements document + +**Key principles:** +- Complement existing frameworks (JUnit/TestNG), don't replace them +- Focus on exhaustive test data generation and OpenHFT-specific utilities +- Design for AI-assisted test generation and refactoring +- Maintain compatibility with JUnit 4, JUnit 5, and TestNG + +## Commit and PR Guidelines + +1. Subject line <= 72 chars, imperative mood: "Fix roll-cycle offset in ExcerptAppender" +2. Reference JIRA/GitHub issue if exists +3. Body: root cause → fix → measurable impact (use ASCII bullet points) +4. **Run `mvn verify` before opening PR** +5. Target branch for PRs: `ea` (not main) + +## AsciiDoc Formatting + +When editing `.adoc` files: + +**List indentation:** +```asciidoc +- top level +* second level + ** third level +``` + +**Emphasis:** Use `_emphasis_` for italics, `*bold*` for bold + +## Code Structure Enforcement + +The framework includes ArchUnit-based structure verification in `CodeStructureVerifier`: +- Non-internal classes must not extend internal classes +- Main methods must invoke Bootstrap +- DTO aliases must invoke Bootstrap.bootstrap() + +These rules are tested and enforced at build time. \ No newline at end of file diff --git a/README.adoc b/README.adoc index 1f9719c5..2af602a3 100644 --- a/README.adoc +++ b/README.adoc @@ -4,6 +4,8 @@ :toc: macro :toclevels: 2 :icons: font +:lang: en-GB +:source-highlighter: rouge image:https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-test-framework/badge.svg[Maven Central,link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-test-framework] image:https://javadoc.io/badge2/net.openhft/chronicle-test-framework/javadoc.svg[Javadoc,link="https://www.javadoc.io/doc/net.openhft/chronicle-test-framework/latest/index.html"] @@ -237,3 +239,10 @@ They help to group metric counts in common ways. The convenience factories in `Accumulator` expose the first two suppliers for general use. The others are mainly for internal analyses but may be reused when custom behaviour is needed. + +== Quality and static analysis + +Chronicle Test Framework uses the shared Chronicle quality configuration provided by the parent POMs. + +* From an aggregator that includes this module, run `mvn -P quality clean verify` to execute Checkstyle and SpotBugs with coverage checks. +* For a module-focused SpotBugs run on Java 11 or newer, run `mvn -P module-quality clean verify` in the `Chronicle-Test-Framework` project. diff --git a/pom.xml b/pom.xml index de258c03..e8136040 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ net.openhft third-party-bom - 3.27ea5 + 3.27ea7 pom import @@ -129,6 +129,81 @@ + + + quality + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + validate + validate + + check + + + + + ${checkstyle.config.location} + true + true + true + ${checkstyle.violationSeverity} + + + + com.puppycrawl.tools + checkstyle + 10.26.1 + + + net.openhft + chronicle-quality-rules + 1.27.0-SNAPSHOT + + + + + com.github.spotbugs + spotbugs-maven-plugin + + 4.9.8.1 + + Max + Low + true + true + + net/openhft/quality/spotbugs27/chronicle-spotbugs-include.xml + net/openhft/quality/spotbugs27/chronicle-spotbugs-exclude.xml + + + + net.openhft + chronicle-quality-rules + 1.27.0-SNAPSHOT + + + + + spotbugs-main + + process-test-classes + + check + + + + + + + + + chronicle-enterprise-snapshots diff --git a/src/main/docs/architecture-overview.adoc b/src/main/docs/architecture-overview.adoc new file mode 100644 index 00000000..5e9714fa --- /dev/null +++ b/src/main/docs/architecture-overview.adoc @@ -0,0 +1,26 @@ += Chronicle Test Framework Architecture Overview +:toc: +:sectnums: +:lang: en-GB +:source-highlighter: rouge + +This document provides a high-level overview of the Chronicle Test Framework (CTF). +It complements the existing requirements under `src/main/docs/project-requirements.adoc` and the README. + +== Context and Role + +Chronicle Test Framework provides support classes and utilities for building rich tests for Chronicle libraries. +It focuses on exhaustive test data generation, dynamic tests and OpenHFT-specific helpers, and is designed to complement frameworks such as JUnit rather than replace them. + +CTF is a Foundation (Zone C) module in the Chronicle stack, supporting testing across higher-level components like Chronicle Queue, Chronicle Map, Chronicle Wire and Chronicle Threads. + +== Core Abstractions + +CTF exposes: + +* data-generation utilities such as `Permutation`, `Combination` and `Product` for creating test data sets; +* helper classes and extensions for JUnit-based tests (for example dynamic test support via `@TestFactory`); +* OpenHFT-focused utilities for testing Chronicle components (as described in the existing project requirements). + +Detailed requirements, including AI-driven and OpenHFT-specific testing enhancements, are specified in `src/main/docs/project-requirements.adoc`. + diff --git a/src/main/docs/decision-log.adoc b/src/main/docs/decision-log.adoc new file mode 100644 index 00000000..ac8df269 --- /dev/null +++ b/src/main/docs/decision-log.adoc @@ -0,0 +1,97 @@ += Chronicle Test Framework Decision Log +:toc: +:sectnums: +:lang: en-GB +:source-highlighter: rouge +:icons: font + +This document records the significant architectural and design decisions for the Chronicle Test Framework (CTF). It serves as a historical record and context provider for developers and AI agents. The primary design and roadmap decisions are also captured in the project requirements and research documents; this log summarises the key choices and their rationale. + +== Decision Index + +* Use separate `src/main/docs/project-requirements.adoc` as the detailed requirements artefact for CTF. + +== Decisions + +=== [CTF-DOC-001] Adoption of Architecture Decision Records + +- Date: 2025-11-20 +- Context: +* As the framework evolves, especially with the integration of AI-driven development, it is crucial to maintain a clear history of *why* decisions were made. +* We need a standard format that is easily parseable by both humans and AI agents. +- Decision Statement: +* Maintain this `decision-log.adoc` file in `src/main/docs/`. +* Use the Nine-Box taxonomy for tagging decisions (FN, NF-P, NF-S, etc.) as defined in `AGENTS.md`. +* Follow the decision record template defined in `AGENTS.md`. +- Alternatives Considered: +* [No formal log]: +** *Description:* Rely on Git commit messages and PR descriptions. +** *Pros:* Less overhead during development. +** *Cons:* High-level reasoning becomes hard to find; context is lost over time; difficult for AI to query systematically. +* [External Wiki]: +** *Description:* Store decisions in Confluence or GitHub Wiki. +** *Pros:* Rich formatting, easier collaboration for non-developers. +** *Cons:* Disconnected from the code (prone to drift); harder for AI agents analysing the repository to access context. +- Rationale for Decision: +* Keeping the decision log co-located with the code (`docs-as-code`) keeps documentation in sync with the codebase. +* The structured AsciiDoc format allows for automated parsing and better context injection for LLMs. +- Impact & Consequences: +* Developers must update this file when making significant changes. +* Provides a single source of truth for architectural intent. +- What are the trade-offs made? +* Slight increase in contribution friction (updating docs) in exchange for long-term clarity. +- Notes/Links: +** See `AGENTS.md` for the full template and tagging structure. + +=== [CTF-FN-002] Strategy for AI-Driven Enhancement + +- Date: 2025-11-20 +- Context: +* The Chronicle Test Framework is being modernised to support high-performance testing in the OpenHFT ecosystem. +* There is a strategic goal to leverage AI for test generation, refactoring, and analysis. +- Decision Statement: +* Adopt the requirements and strategy outlined in `project-requirements.adoc`. +* Design new APIs to be "AI-consumable" (strongly typed, clear contracts, semantic annotations). +* Introduce "AI-Identifiable Refactoring Opportunities" as a core functional requirement. +- Alternatives Considered: +* [Status Quo]: +** *Description:* Continue with the existing feature set (Combinations/Permutations only). +** *Pros:* Stable, no new development effort. +** *Cons:* Misses the opportunity to standardise testing across OpenHFT; fails to leverage modern AI capabilities. +* [Complete Rewrite]: +** *Description:* Build a new framework from scratch. +** *Pros:* No technical debt. +** *Cons:* Breaks compatibility for existing users; high effort; discards proven components like the `Permutation` generator. +- Rationale for Decision: +* Enhancing the existing framework builds on its strengths while addressing limitations. +* Designing for AI keeps the framework relevant in an AI-assisted development landscape. +- Impact & Consequences: +* The API surface will grow to support OpenHFT-specific testing utilities (e.g., for Chronicle Queue and Map). +* Deprecation of older, less "AI-friendly" patterns may be necessary over time. +- What are the trade-offs made? +* Complexity increases to support the new abstraction layers. +- Notes/Links: +** See `src/main/docs/project-requirements.adoc` for full details. + +=== [CTF-NF-P-003] Performance-First Design for Data Generators + +- Date: 2025-11-20 +- Context: +* OpenHFT libraries are performance-critical. +* Exhaustive testing using permutations and combinations can easily lead to exponential runtimes. +- Decision Statement: +* CTF's data generation utilities (`Permutation`, `Combination`, `Product`) must remain highly performant. +* Guidance must be provided to users on managing test suite execution time (e.g., using `limit()`, sampling, or `@Tag` for slow tests). +- Alternatives Considered: +* [Lazy Evaluation Only]: +** *Description:* Enforce strict lazy evaluation streams for all generators. +** *Pros:* Minimal memory footprint. +** *Cons:* Already largely implemented but requires careful API design to ensure users do not accidentally materialise massive sets. +- Rationale for Decision: +* Ensure CTF does not become a bottleneck in performance-sensitive OpenHFT testing environments. +- Impact & Consequences: +* Internal implementations of generators must be optimised for low allocation and high throughput. +- What are the trade-offs made? +* API usage might require more care from the developer to avoid long-running tests. +- Notes/Links: +** Reference `REQ-NFR-PERF-001`. diff --git a/src/main/adoc/project-requirements.adoc b/src/main/docs/project-requirements.adoc similarity index 83% rename from src/main/adoc/project-requirements.adoc rename to src/main/docs/project-requirements.adoc index dfc67d74..3b8a52e9 100644 --- a/src/main/adoc/project-requirements.adoc +++ b/src/main/docs/project-requirements.adoc @@ -1,21 +1,26 @@ = Requirements Document: Enhancing Chronicle Test Framework with AI Support -:toc: left +:toc: :lang: en-GB +:sectnums: +:source-highlighter: rouge -== 1. Introduction and Purpose == +== Introduction and Purpose -This document outlines the requirements for enhancing the Chronicle Test Framework (CTF). The primary goals are to improve its overall quality, ease of adoption, deepen its integration with the OpenHFT ecosystem, and strategically incorporate Artificial Intelligence (AI) to assist in its development and application. +This document outlines the requirements for enhancing the Chronicle Test Framework (CTF). +The primary goals are to improve its overall quality, ease of adoption, deepen its integration with the OpenHFT ecosystem, and strategically incorporate Artificial Intelligence (AI) to assist in its development and application. -The envisioned framework aims to **complement existing testing frameworks** like JUnit and TestNG, rather than replacing them, by providing specialized capabilities, particularly for exhaustive test data generation and testing high-performance OpenHFT components. This document will serve as a guide for the development team in evolving CTF. +The envisioned framework aims to **complement existing testing frameworks** like JUnit and TestNG, rather than replacing them, by providing specialized capabilities, particularly for exhaustive test data generation and testing high-performance OpenHFT components. +This document will serve as a guide for the development team in evolving CTF. The requirements are derived from: * An in-depth analysis titled "Enhancing Chronicle Test Framework: A Comparative Analysis and Roadmap for AI-Driven Improvements." * A comparative analysis document titled "Chronicle Test Framework: Comparative Analysis and Improvement Opportunities." -== 2. Current State of Chronicle Test Framework == +== Current State of Chronicle Test Framework -The Chronicle Test Framework (CTF) is a Java library offering support classes tailored for crafting JUnit tests, compatible with both JUnit 4 and JUnit 5. Its core strength lies in generating a comprehensive range of test data combinations and permutations through utilities like `Permutation.of()`, `Combination.of()`, and `Product.of()`. These are primarily leveraged with JUnit 5's `@TestFactory` for dynamic test generation. +The Chronicle Test Framework (CTF) is a Java library offering support classes tailored for crafting JUnit tests, compatible with both JUnit 4 and JUnit 5. Its core strength lies in generating a comprehensive range of test data combinations and permutations through utilities like `Permutation.of()`, `Combination.of()`, and `Product.of()`. +These are primarily leveraged with JUnit 5's `@TestFactory` for dynamic test generation. Identified strengths include: @@ -33,7 +38,7 @@ Identified limitations include: These limitations, particularly the lack of formal design principles and a broader feature set, present challenges for leveraging AI effectively in the framework's evolution. -== 3. High-Level Goals for Enhancement == +== High-Level Goals for Enhancement The enhancement of CTF will be guided by the following high-level goals: @@ -43,52 +48,61 @@ The enhancement of CTF will be guided by the following high-level goals: * **HLG-4: Enable AI-Driven Development and Usage:** Design CTF to facilitate AI-assisted test generation, refactoring, and analysis, as well as using AI to improve CTF itself. * **HLG-5: Complement Existing Frameworks:** Ensure CTF continues to work alongside and enhance existing frameworks like JUnit and TestNG without aiming to replace their core functionalities. -== 4. Functional Requirements == +== Functional Requirements This section details the functional requirements for enhancing CTF. -=== 4.1. Core Framework Enhancements === +=== Core Framework Enhancements These requirements focus on modernizing CTF's core capabilities, drawing inspiration from established testing frameworks. +[[REQ-FR-CORE-001]] REQ-FR-CORE-001: Expanded Annotation Support :: **Description:** Introduce a suite of CTF-specific annotations for declarative configuration, lifecycle management, and metadata, tailored for OpenHFT contexts. -**Rationale:** Reduce boilerplate, improve test readability and maintainability. Provides clear markers for AI to understand test structure and dependencies. +**Rationale:** Reduce boilerplate, improve test readability and maintainability. +Provides clear markers for AI to understand test structure and dependencies. **Examples:** `@ChronicleTestConfiguration`, `@DataSource`, specialized OpenHFT component lifecycle annotations. **Reference:** Research Sec 3.1, User Doc "Opportunities for Improvement - JUnit 5 Integration Enhancements". +[[REQ-FR-CORE-002]] REQ-FR-CORE-002: Enhanced Parameterized and Dynamic Test Capabilities :: **Description:** Provide more integrated and intuitive mechanisms for parameter resolution and descriptive test naming for tests using CTF-generated data, akin to JUnit 5's `@ParameterizedTest` sources or TestNG's `@DataProvider`. **Rationale:** Simplify the creation and management of parameterized tests leveraging CTF's data generation. **Reference:** Research Sec 3.1. +[[REQ-FR-CORE-003]] REQ-FR-CORE-003: Improved Assertion Capabilities :: **Description:** Enhance assertion capabilities through one or a combination of: * **Option A:** Deep, seamless integration with AssertJ. * **Option B:** Development of a focused set of native fluent assertions within CTF, specifically for common OpenHFT data structures and testing scenarios. -**Rationale:** Improve test readability, maintainability, and developer productivity. Fluent assertions are preferred by developers. +**Rationale:** Improve test readability, maintainability, and developer productivity. +Fluent assertions are preferred by developers. **Reference:** Research Sec 3.1, User Doc "Fluent and Expressive Assertions", "Opportunities for Improvement - Leverage AssertJ". +[[REQ-FR-CORE-004]] REQ-FR-CORE-004: Formal Extensibility Model :: **Description:** Design and implement a formal extension model (e.g., inspired by JUnit 5's `@ExtendWith` or TestNG's listeners). **Rationale:** Foster broader adoption, enable community contributions, allow tailoring to specific project needs, and provide clear integration points for AI-generated code or custom analysis. **Possible Extensions:** Custom parameter resolvers, lifecycle callbacks, test instance post-processors, custom test execution behavior. **Reference:** Research Sec 3.1. +[[REQ-FR-CORE-005]] REQ-FR-CORE-005: TestNG Integration Support :: **Description:** Provide official support and examples for using CTF data generation capabilities with TestNG's `@DataProvider` mechanism. **Rationale:** Broaden CTF's user base beyond JUnit users and demonstrate its flexibility. **Reference:** User Doc "Test Lifecycle and Configuration Ease", "Opportunities for Improvement - TestNG Support". -=== 4.2. Developer Experience and Usability Improvements === +=== Developer Experience and Usability Improvements These requirements aim to make CTF more user-friendly and easier to adopt. +[[REQ-FR-UX-001]] REQ-FR-UX-001: API Simplification for Common Scenarios :: **Description:** Identify common usage patterns of CTF's generators and provide convenience APIs, builders, or pre-configured generators to encapsulate complexity. **Rationale:** Lower the learning curve for new users and make CTF more readily applicable for simpler testing needs. **Reference:** Research Sec 3.2. +[[REQ-FR-UX-002]] REQ-FR-UX-002: Comprehensive Documentation and Illustrative Examples :: **Description:** Significantly expand documentation to include: * "Getting Started" guide. @@ -101,12 +115,14 @@ REQ-FR-UX-002: Comprehensive Documentation and Illustrative Examples :: **Rationale:** Paramount for adoption, effective use, and reducing the learning curve. **Reference:** Research Sec 3.2, User Doc "Documentation Quality", "Opportunities for Improvement - Expanded Documentation". -=== 4.3. Deepened Integration with OpenHFT Ecosystem === +=== Deepened Integration with OpenHFT Ecosystem These requirements focus on providing specialized testing utilities for core OpenHFT libraries. +[[REQ-FR-OHFT-001]] REQ-FR-OHFT-001: Specialized Testing Utilities for Chronicle Queue :: -**Description:** Develop utilities such as `TestAppender`, `TestTailer`, assertion helpers for message content, and utilities for programmatic setup/teardown of test queues. Include helpers for testing specific queue behaviors. +**Description:** Develop utilities such as `TestAppender`, `TestTailer`, assertion helpers for message content, and utilities for programmatic setup/teardown of test queues. +Include helpers for testing specific queue behaviors. **Rationale:** Simplify testing of Chronicle Queue, encapsulate common patterns, and reduce boilerplate. **Reference:** Research Sec 3.3. **Conceptual Example:** @@ -130,6 +146,7 @@ REQ-FR-OHFT-001: Specialized Testing Utilities for Chronicle Queue :: } ---- +[[REQ-FR-OHFT-002]] REQ-FR-OHFT-002: Helpers for Chronicle Map Testing :: **Description:** Introduce fixtures/extensions for creating/managing test `ChronicleMap` instances, rich assertions for map properties and values (especially `BytesMarshallable`), and utilities for verifying concurrent access or common interaction patterns (`getUsing`, `acquireUsing`). **Rationale:** Simplify testing of Chronicle Map, provide powerful assertions for complex data types. @@ -155,21 +172,25 @@ REQ-FR-OHFT-002: Helpers for Chronicle Map Testing :: } ---- +[[REQ-FR-OHFT-003]] REQ-FR-OHFT-003: Support for Chronicle Wire Serialization Testing :: **Description:** Create utilities for testing serialization/deserialization of `Marshallable` objects across different `WireTypes`, helpers for testing schema evolution, and assertions for inspecting raw `Bytes` content. **Rationale:** Ensure data integrity and interoperability for components using Chronicle Wire. **Reference:** Research Sec 3.3. +[[REQ-FR-OHFT-004]] REQ-FR-OHFT-004: Leveraging Chronicle Threads for Concurrency Testing :: **Description:** Offer utilities for managing `EventLoop` instances in tests, helpers for testing `Pauser` strategies, and assertions/patterns for verifying thread safety and concurrent behavior. **Rationale:** Simplify the setup and verification of complex concurrent test scenarios. **Reference:** Research Sec 3.3. +[[REQ-FR-OHFT-005]] REQ-FR-OHFT-005: Multi-Process Test Support :: **Description:** Provide documented, high-level utilities or patterns for creating and managing multi-process tests, including lifecycle management and output capture. **Rationale:** Facilitate testing of inter-process communication scenarios common with OpenHFT libraries. **Reference:** User Doc "Suitability for Low-Latency and Performance-Critical Tests". +[[REQ-FR-OHFT-006]] REQ-FR-OHFT-006: Resource and Concurrency Test Utilities :: **Description:** Introduce utilities to aid in testing resource management and concurrency aspects critical for OpenHFT libraries: * **Thread Leak Detection:** A utility or extension to check for orphaned threads after test execution. @@ -178,15 +199,17 @@ REQ-FR-OHFT-006: Resource and Concurrency Test Utilities :: **Rationale:** Address common pain points in testing high-performance, resource-intensive applications and ensure test reliability. **Reference:** User Doc "Opportunities for Improvement - Resource and Concurrency Utilities". -=== 4.4. AI-Specific Functional Requirements === +=== AI-Specific Functional Requirements These requirements are specifically aimed at designing CTF to effectively leverage and support AI tools. +[[REQ-FR-AI-001]] REQ-FR-AI-001: AI-Identifiable Refactoring Opportunities :: **Description:** CTF's new utilities, annotations, and extensions (as defined in REQ-FR-CORE and REQ-FR-OHFT) must be designed to serve as clear, beneficial, higher-level abstractions that AI tools can refactor existing tests to use. **Rationale:** Enable AI to automate the modernization and simplification of test suites using CTF features. **Reference:** Research Sec 3.4. +[[REQ-FR-AI-002]] REQ-FR-AI-002: Patterns for AI-Assisted Test Generation :: **Description:** CTF shall provide and document patterns for how AI can: * Use CTF's data generators (`Permutation`, `Combination`, `Product`) for method parameters or message payloads in AI-generated tests. @@ -195,73 +218,94 @@ REQ-FR-AI-002: Patterns for AI-Assisted Test Generation :: **Rationale:** Combine CTF's structured generation and OpenHFT-specific knowledge with AI's code generation and analysis capabilities. **Reference:** Research Sec 3.4. +[[REQ-FR-AI-003]] REQ-FR-AI-003: AI-Consumable API Design :: **Description:** All new CTF APIs (annotations, extension points, fluent builders, assertion methods) must be designed with AI consumption in mind, ensuring they are: * **Clearly Defined and Strongly Typed:** Minimize ambiguity, have clear contracts. * **Discoverable:** Comprehensive Javadoc, consistent naming, logical structure. * **Composable:** Designed as smaller, composable units of functionality. -**Rationale:** Facilitate correct and effective use of CTF features by AI tools. Good API design for humans is critical for AI. +**Rationale:** Facilitate correct and effective use of CTF features by AI tools. +Good API design for humans is critical for AI. **Reference:** Research Sec 3.4. +[[REQ-FR-AI-004]] REQ-FR-AI-004: Semantic Information Conveyance for AI :: **Description:** CTF APIs, especially annotations, should be designed to carry semantic information about the test's intent or the configuration of the component under test, beyond syntactic structure. **Rationale:** Enable AI to make more intelligent suggestions, generate more effective tests, and understand the domain-specific (OpenHFT) context. **Example:** An annotation like `@ChronicleQueueTest(role="messageConsumer", expectedThroughput="100k_msgs_sec")` offers richer context than a simple `@Test`. **Reference:** Research Sec 3.4. -== 5. Non-Functional Requirements == +== Non-Functional Requirements This section details the non-functional requirements for CTF. +[[REQ-NFR-PERF-001]] REQ-NFR-PERF-001: Performance of CTF :: -**Description:** CTF's data generation and utility functions should be performant and not add undue overhead to test execution. Guidance should be provided on managing test suite execution time when using exhaustive generation. +**Description:** CTF's data generation and utility functions should be performant and not add undue overhead to test execution. +Guidance should be provided on managing test suite execution time when using exhaustive generation. **Rationale:** Ensure CTF itself does not become a bottleneck, especially in performance-sensitive OpenHFT testing environments. **Reference:** User Doc "Suitability for Low-Latency and Performance-Critical Tests". -*REQ-NFR-USAB-001: Usability and Learnability :: -**Description:** The API should be intuitive, consistent, and easy to learn, particularly for developers familiar with Java and standard testing frameworks. The learning curve should be minimized. +[[REQ-NFR-USAB-001]] +REQ-NFR-USAB-001: Usability and Learnability :: +**Description:** The API should be intuitive, consistent, and easy to learn, particularly for developers familiar with Java and standard testing frameworks. +The learning curve should be minimized. **Rationale:** Critical for adoption and effective use. **Reference:** User Doc "API Consistency and Learning Curve". +[[REQ-NFR-MAIN-001]] REQ-NFR-MAIN-001: Maintainability :: -**Description:** CTF's codebase should be well-structured, documented, and testable to ensure ease of maintenance and future enhancements. Design principles like SRP and ISP should be considered. +**Description:** CTF's codebase should be well-structured, documented, and testable to ensure ease of maintenance and future enhancements. +Design principles like SRP and ISP should be considered. **Rationale:** Long-term health and evolution of the framework. **Reference:** Research Sec 3.4. +[[REQ-NFR-COMP-001]] REQ-NFR-COMP-001: Compatibility :: -**Description:** CTF must maintain compatibility with JUnit 4 and JUnit 5. Integration with TestNG should be supported as a complementary approach. Compatibility with relevant Java versions must be clearly stated. +**Description:** CTF must maintain compatibility with JUnit 4 and JUnit 5. Integration with TestNG should be supported as a complementary approach. +Compatibility with relevant Java versions must be clearly stated. **Rationale:** Support existing user bases and allow flexibility in framework choice. **Reference:** CTF Current State, User Doc "Test Lifecycle and Configuration Ease". +[[REQ-NFR-DOC-001]] REQ-NFR-DOC-001: High-Quality Documentation :: -**Description:** All features, APIs, extension points, and usage patterns must be thoroughly documented with clear examples. (Covered in REQ-FR-UX-002 but emphasized here as an NFR). +**Description:** All features, APIs, extension points, and usage patterns must be thoroughly documented with clear examples. +(Covered in REQ-FR-UX-002 but emphasized here as an NFR). **Rationale:** Essential for user adoption, understanding, and effective utilization. +[[REQ-NFR-STAB-001]] REQ-NFR-STAB-001: Stability and Versioning :: -**Description:** CTF should move towards stable versioning, with clear communication about the stability level of releases (e.g., milestones, RCs, GA). Compatibility between CTF versions and OpenHFT library versions should be indicated. +**Description:** CTF should move towards stable versioning, with clear communication about the stability level of releases (e.g., milestones, RCs, GA). +Compatibility between CTF versions and OpenHFT library versions should be indicated. **Rationale:** Improve developer confidence and simplify dependency management. **Reference:** User Doc "Opportunities for Improvement - Standardization with Testing Conventions". -== 6. AI-Driven Development and Application Strategy == +== AI-Driven Development and Application Strategy The enhancement of CTF will proactively incorporate AI in two main ways: -=== 6.1. AI in the Development *of* CTF === +=== AI in the Development *of* CTF + AI-DEV-CTF-001: Suggesting Refinements :: AI tools may be used to analyze the existing CTF codebase and the proposed APIs to suggest refinements, identify potential inconsistencies, or propose alternative designs based on common Java and testing framework patterns. I-DEV-CTF-002: Boilerplate Code Generation :: For implementing well-defined, repetitive structures within CTF (e.g., new assertion methods following a pattern, boilerplate for new OpenHFT utility classes), AI can assist in generating initial code. AI-DEV-CTF-003: Documentation Assistance:** AI tools can help in generating Javadoc stubs, summarizing features for release notes, or even drafting initial sections of user guides based on code and requirements. -=== 6.2. AI in the Application *by Users of* CTF === -This is primarily covered by REQ-FR-AI-* requirements. The strategy is to make CTF "AI-friendly" so that: +=== AI in the Application *by Users of* CTF + +This is primarily covered by REQ-FR-AI-* requirements. +The strategy is to make CTF "AI-friendly" so that: AI-APP-CTF-001: AI can understand CTF test structures :: Semantic annotations and clear APIs will enable AI to better parse and understand tests written with CTF. AI-APP-CTF-002: AI can leverage CTF features for test generation :: AI tools can be guided to use CTF's data generators and OpenHFT-specific utilities to create more comprehensive and relevant tests. -* _Example:_ An AI agent, using `ChronicleQueueTestUtil` and `Permutation.of()`, could generate tests that try every ordering of different message types written to a queue, verifying that each ordering is processed correctly. +* _Example:_ An AI agent, using `ChronicleQueueTestUtil` and `Permutation.of()`, could generate tests that try every ordering of different message types written to a queue, verifying that each ordering is processed correctly. I-APP-CTF-003: AI can assist in refactoring tests to use CTF :: As CTF evolves with more powerful utilities, AI can help migrate older tests (or tests not using CTF optimally) to leverage these new features, improving test quality and conciseness. AI-APP-CTF-004: AI can perform advanced test analysis :: With richer semantic information from CTF tests, AI might be able to perform more sophisticated analyses, such as identifying redundant tests, suggesting coverage improvements for specific OpenHFT behaviors, or even predicting flaky tests based on patterns. By embedding AI considerations into the design of CTF, the framework will not only be improved by AI but will also empower its users to leverage AI for more effective testing within the OpenHFT ecosystem. -== 7. Conclusion == +== Conclusion -The Chronicle Test Framework has a solid foundation in test data generation. By implementing the requirements outlined in this document, CTF will evolve into a more comprehensive, user-friendly, and powerful testing tool, especially for the OpenHFT ecosystem. The strategic incorporation of AI-support features will position CTF as a forward-looking framework, enabling new levels of efficiency and intelligence in software testing. The key is to build upon its unique strengths while addressing current limitations and embracing modern testing paradigms, all while ensuring it remains a valuable complement to mainstream testing frameworks. \ No newline at end of file +The Chronicle Test Framework has a solid foundation in test data generation. +By implementing the requirements outlined in this document, CTF will evolve into a more comprehensive, user-friendly, and powerful testing tool, especially for the OpenHFT ecosystem. +The strategic incorporation of AI-support features will position CTF as a forward-looking framework, enabling new levels of efficiency and intelligence in software testing. +The key is to build upon its unique strengths while addressing current limitations and embracing modern testing paradigms, all while ensuring it remains a valuable complement to mainstream testing frameworks. diff --git a/src/main/docs/testing-strategy.adoc b/src/main/docs/testing-strategy.adoc new file mode 100644 index 00000000..4e0ff792 --- /dev/null +++ b/src/main/docs/testing-strategy.adoc @@ -0,0 +1,30 @@ += Chronicle Test Framework Testing Strategy +:toc: +:sectnums: +:lang: en-GB +:source-highlighter: rouge + +Chronicle Test Framework is both a consumer and a supplier of tests. +This document explains how CTF itself is tested, and how it is intended to support tests in other modules. + +== Objectives + +Testing for CTF aims to: + +* ensure the core data-generation and helper utilities behave correctly; +* validate the functional requirements in `src/main/docs/project-requirements.adoc`; +* keep examples and documentation in sync with library behaviour. + +== Unit and Integration Tests + +Unit and integration tests under `src/test/java` exercise: + +* `Permutation`, `Combination`, `Product` and related data-generation utilities; +* JUnit integration points used in the examples and documentation; +* any helper classes that are provided for Chronicle components. + +== Traceability + +`src/main/docs/project-requirements.adoc` remains the central requirements artefact for CTF. +This summary, together with the existing research and roadmap documents, provides sufficient coverage for the ISO 9001 checklist used by the repository. + diff --git a/src/main/java/net/openhft/chronicle/testframework/Permutation.java b/src/main/java/net/openhft/chronicle/testframework/Permutation.java index 732f203a..9e5eb315 100644 --- a/src/main/java/net/openhft/chronicle/testframework/Permutation.java +++ b/src/main/java/net/openhft/chronicle/testframework/Permutation.java @@ -37,7 +37,7 @@ * sizes. Consider sampling when dealing with larger collections. *

* General permutation support from - * http://minborgsjavapot.blogspot.com/2015/07/java-8-master-permutations.html + * ... * * @author Per Minborg */ diff --git a/src/main/java/net/openhft/chronicle/testframework/Series.java b/src/main/java/net/openhft/chronicle/testframework/Series.java index d04e2bdd..804f86dd 100644 --- a/src/main/java/net/openhft/chronicle/testframework/Series.java +++ b/src/main/java/net/openhft/chronicle/testframework/Series.java @@ -64,5 +64,4 @@ public static LongStream fibonacci() { public static LongStream primes() { return SeriesUtil.primes(); // Delegating to internal utility } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/apimetrics/package-info.java b/src/main/java/net/openhft/chronicle/testframework/apimetrics/package-info.java index bb78a596..9588f3ba 100644 --- a/src/main/java/net/openhft/chronicle/testframework/apimetrics/package-info.java +++ b/src/main/java/net/openhft/chronicle/testframework/apimetrics/package-info.java @@ -16,8 +16,8 @@ * instance with the builder. That instance can be applied to the chosen * packages. * - *

Example usage might include creating customised {@link Metric} instances and - * a tailored {@link Accumulator}, followed by the builder workflow to analyse + *

Example usage might include creating customised {@link net.openhft.chronicle.testframework.apimetrics.Metric} instances and + * a tailored {@link net.openhft.chronicle.testframework.apimetrics.Accumulator}, followed by the builder workflow to analyse * packages for compliance with specific coding standards, detecting patterns, or * generating reports for code quality assurance. Typical use cases include * maintaining API consistency across releases. diff --git a/src/main/java/net/openhft/chronicle/testframework/dto/DtoTester.java b/src/main/java/net/openhft/chronicle/testframework/dto/DtoTester.java index 40199d53..0012b71b 100644 --- a/src/main/java/net/openhft/chronicle/testframework/dto/DtoTester.java +++ b/src/main/java/net/openhft/chronicle/testframework/dto/DtoTester.java @@ -94,7 +94,7 @@ interface Builder { * @param mutator mutation logic * @return this builder for chaining */ - @NotNull Builder addMutator(@NotNull MutatorType type, + @NotNull Builder addMutator(@NotNull MutatorType type, @NotNull String mutatorName, @NotNull Consumer mutator); diff --git a/src/main/java/net/openhft/chronicle/testframework/function/ThrowingConsumerException.java b/src/main/java/net/openhft/chronicle/testframework/function/ThrowingConsumerException.java index 5ad651a3..fdf0a466 100644 --- a/src/main/java/net/openhft/chronicle/testframework/function/ThrowingConsumerException.java +++ b/src/main/java/net/openhft/chronicle/testframework/function/ThrowingConsumerException.java @@ -15,7 +15,7 @@ public class ThrowingConsumerException extends RuntimeException { /** * The serial version UID for the serialization mechanism. */ - static final long serialVersionUID = -8237762538281151227L; + private static final long serialVersionUID = -8237762538281151227L; /** * Constructs a new ThrowingConsumerException with the specified cause. diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/DelegationBuilder.java b/src/main/java/net/openhft/chronicle/testframework/internal/DelegationBuilder.java index bd23ea36..9b6a2998 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/DelegationBuilder.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/DelegationBuilder.java @@ -81,5 +81,4 @@ public T build() { return method.invoke(delegate, args); }); } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/PermutationUtil.java b/src/main/java/net/openhft/chronicle/testframework/internal/PermutationUtil.java index 7ba7e22a..604232a0 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/PermutationUtil.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/PermutationUtil.java @@ -27,8 +27,8 @@ * Utility methods for enumerating permutations. The algorithm maps the * permutation number to the factorial number system and selects elements one * by one. It was adapted from - * http://minborgsjavapot.blogspot.com/2015/07/java-8-master-permutations.html - * + * ... + *

* Valid inputs are limited so that all factorial calculations fit within a * {@code long}. Collections larger than twenty items will therefore cause an * {@link IllegalArgumentException}. diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/SeriesUtil.java b/src/main/java/net/openhft/chronicle/testframework/internal/SeriesUtil.java index 633e31df..47df71dd 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/SeriesUtil.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/SeriesUtil.java @@ -6,6 +6,13 @@ import java.util.stream.LongStream; import java.util.stream.Stream; +/** + * Helper methods for generating number series used in property-based or parameterised tests. + *

+ * The sequences include powers of two and their neighbours, Fibonacci numbers and primes, + * all exposed as {@link LongStream} instances so that tests can consume them lazily and + * compose them with additional filters or bounds as required. + */ public final class SeriesUtil { private SeriesUtil() { @@ -51,5 +58,4 @@ private static boolean isPrime(long number) { return LongStream.rangeClosed(2, (int) (Math.sqrt(number))) .allMatch(n -> number % n != 0); } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/VanillaExceptionTracker.java b/src/main/java/net/openhft/chronicle/testframework/internal/VanillaExceptionTracker.java index ebc7e1b7..a5df586c 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/VanillaExceptionTracker.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/VanillaExceptionTracker.java @@ -115,7 +115,7 @@ public void checkExceptions() { if (hasExceptions()) { dumpException(); - final String msg = exceptions.size() + " exceptions were detected: " + exceptions.keySet().stream().map(messageExtractor::apply).collect(Collectors.joining(", ")); + final String msg = exceptions.size() + " exceptions were detected: " + exceptions.keySet().stream().map(messageExtractor).collect(Collectors.joining(", ")); throw new AssertionError(msg); } resetRunnable.run(); diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/ApiMetricsUtil.java b/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/ApiMetricsUtil.java index 7406591f..f0ce1d2d 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/ApiMetricsUtil.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/ApiMetricsUtil.java @@ -13,5 +13,4 @@ final class ApiMetricsUtil { // Suppresses default constructor, ensuring non-instantiability. private ApiMetricsUtil() { } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetrics.java b/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetrics.java index 549e7de3..d3791877 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetrics.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetrics.java @@ -28,7 +28,6 @@ * internal analysis. Both methods supply the accumulators in the order they * were added to the builder. */ - public final class StandardApiMetrics implements ApiMetrics { private final Set accumulators; diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardMetrics.java b/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardMetrics.java index 0940f22e..4520f40c 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardMetrics.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardMetrics.java @@ -40,7 +40,6 @@ * * This class cannot be instantiated. */ - final class StandardMetrics { static final Metric CLASS_PUBLIC = Metric.of(ClassInfo.class, predicateOfClass(Modifier::isPublic), "Class Public", 10); diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/CodeStructureVerifier.java b/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/CodeStructureVerifier.java index 2387155a..6acd4792 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/CodeStructureVerifier.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/CodeStructureVerifier.java @@ -179,6 +179,8 @@ private void installDefaultRules() { } private JavaClasses getJavaClasses() { + // Skip archive URIs entirely; jar:file schemes cannot be resolved via Paths.get without mounting zipfs. + importOptions.add(location -> !"jar".equalsIgnoreCase(location.asURI().getScheme())); skipClasses(); ClassFileImporter classFileImporter = new ClassFileImporter(importOptions); if (clazz != null) { @@ -223,5 +225,4 @@ public CodeStructureVerifier build() { } } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/DtoAliasMustInvokeBootstrapRuleSupplier.java b/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/DtoAliasMustInvokeBootstrapRuleSupplier.java index f7c2dd13..4d33f7a5 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/DtoAliasMustInvokeBootstrapRuleSupplier.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/DtoAliasMustInvokeBootstrapRuleSupplier.java @@ -83,5 +83,4 @@ private static long getMethodInvocationsFromCodeUnits(List codeUni return totalCount; } } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/NonInternalClassesMustNotExtendInternalClassesRuleSupplier.java b/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/NonInternalClassesMustNotExtendInternalClassesRuleSupplier.java index ad776775..3981a43e 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/NonInternalClassesMustNotExtendInternalClassesRuleSupplier.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/codestructure/rules/NonInternalClassesMustNotExtendInternalClassesRuleSupplier.java @@ -41,5 +41,4 @@ public void check(JavaClass javaClass, ConditionEvents events) { } }).allowEmptyShould(true); } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/dto/DtoTesterBuilder.java b/src/main/java/net/openhft/chronicle/testframework/internal/dto/DtoTesterBuilder.java index e8ef6355..04d93b04 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/dto/DtoTesterBuilder.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/dto/DtoTesterBuilder.java @@ -104,7 +104,7 @@ public DtoTester.Builder withValidator(@NotNull final Consumer val */ @Override @NotNull - public DtoTester.Builder addMutator(@NotNull final DtoTester.MutatorType type, + public DtoTester.Builder addMutator(@NotNull final DtoTester.MutatorType type, @NotNull final String mutatorName, @NotNull final Consumer mutator) { switch (type) { @@ -121,17 +121,6 @@ public DtoTester.Builder addMutator(@NotNull final DtoTester.MutatorType } return this; } -/* - - @Override - @NotNull - public DtoTester.Builder addValidationRule(@NotNull final String ruleName, - @NotNull final Predicate validator) { - validations.add(new NamedPredicate<>(ruleName, validator)); - return this; - } - - */ /** * Creates a {@link DtoTester} using the information added so far. diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/dto/StandardDtoTester.java b/src/main/java/net/openhft/chronicle/testframework/internal/dto/StandardDtoTester.java index b51b74b6..6238ac69 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/dto/StandardDtoTester.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/dto/StandardDtoTester.java @@ -9,8 +9,6 @@ import org.jetbrains.annotations.NotNull; import java.util.*; -import java.util.function.BiFunction; -import java.util.function.Consumer; import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; @@ -55,6 +53,7 @@ private void assertInstanceCanBeCreated() { } private void assertConstructorNonReuse() { + //noinspection ObjectEquality,ExpressionComparedToItself if (createInstance() == createInstance()) throw new AssertionError("The constructor must produce new fresh instances"); } @@ -168,22 +167,6 @@ private void assertOptionalsDoesNotPass(@NotNull final Set> set) } } - private Collection check(final Consumer postMutatorAction, - final BiFunction tester) { - - final T fresh = createInstance(); - final List failed = newList(); - for (NamedMutator namedMutator : builder.allMutators()) { - final T t = createInstance(); - namedMutator.mutator().accept(t); - postMutatorAction.accept(t); - if (tester.apply(fresh, t)) { - failed.add(namedMutator.name()); - } - } - return failed; - } - private T createInstance() { return builder.supplier().get(); } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaNamedConsumer.java b/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaNamedConsumer.java index bda76c91..ba42972b 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaNamedConsumer.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaNamedConsumer.java @@ -4,6 +4,7 @@ package net.openhft.chronicle.testframework.internal.function; import net.openhft.chronicle.testframework.function.NamedConsumer; +import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; @@ -37,7 +38,7 @@ public void accept(T t) { } @Override - public String name() { + public @NotNull String name() { return name; } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaThrowingConsumer.java b/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaThrowingConsumer.java index a940f55f..904795ad 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaThrowingConsumer.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/function/VanillaThrowingConsumer.java @@ -36,5 +36,4 @@ public void accept(T t) { throw new ThrowingConsumerException(e); } } - } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/ProxyConnection.java b/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/ProxyConnection.java index 6e21af48..91d3b0ca 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/ProxyConnection.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/ProxyConnection.java @@ -44,7 +44,6 @@ public class ProxyConnection implements Closeable, Runnable { * @param inboundChannel The accepted client channel, closed when the run loop terminates * @param remoteAddress Upstream host and port to connect to */ - public ProxyConnection(SocketChannel inboundChannel, InetSocketAddress remoteAddress) { this.inboundChannel = inboundChannel; this.remoteAddress = remoteAddress; diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxy.java b/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxy.java index dd8fadbf..0372ddf8 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxy.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxy.java @@ -105,6 +105,7 @@ public void run() { } for (int i = 0; i < connections.size(); i++) { if (connections.get(i).isFinished()) { + //noinspection resource connections.remove(i); i--; } diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/process/InternalJavaProcessBuilder.java b/src/main/java/net/openhft/chronicle/testframework/internal/process/InternalJavaProcessBuilder.java index fc07f1fc..3abd4564 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/process/InternalJavaProcessBuilder.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/process/InternalJavaProcessBuilder.java @@ -8,10 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; +import java.io.*; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.nio.charset.Charset; @@ -70,16 +67,14 @@ private static Path findJavaBinPath() { *

* ProcessBuilder.inheritIO() didn't play nicely with Maven failsafe plugin *

- * https://maven.apache.org/surefire/maven-failsafe-plugin/faq.html#corruptedstream + * ... */ public static void printProcessOutput(String processName, Process process) { if (LOGGER.isInfoEnabled()) - LOGGER.info( - String.format("%n Output for %s%n stdout:%n%s stderr:%n%s", - processName, - getProcessStdOut(process), - getProcessStdErr(process)) - ); + LOGGER.info("\n Output for {}\n stdout:\n{} stderr:\n{}", + processName, + getProcessStdOut(process), + getProcessStdErr(process)); } /** @@ -175,7 +170,7 @@ public Process start() { if (classpathEntries == null || classpathEntries.length == 0) { classPath = System.getProperty("java.class.path"); } else { - classPath = String.join(System.getProperty("path.separator"), classpathEntries); + classPath = String.join(File.pathSeparator, classpathEntries); } String className = mainClass.getName(); diff --git a/src/main/java/net/openhft/chronicle/testframework/internal/process/package-info.java b/src/main/java/net/openhft/chronicle/testframework/internal/process/package-info.java index ee1876ea..f5ea67d1 100644 --- a/src/main/java/net/openhft/chronicle/testframework/internal/process/package-info.java +++ b/src/main/java/net/openhft/chronicle/testframework/internal/process/package-info.java @@ -3,7 +3,7 @@ */ /** * Contains helpers used to spawn Java processes when tests require them. - * + *

* These classes are for internal use and their behaviour may change without notice. */ package net.openhft.chronicle.testframework.internal.process; diff --git a/src/main/java/net/openhft/chronicle/testframework/mappedfiles/MappedFileUtil.java b/src/main/java/net/openhft/chronicle/testframework/mappedfiles/MappedFileUtil.java index d8aa6c38..e8b315f5 100644 --- a/src/main/java/net/openhft/chronicle/testframework/mappedfiles/MappedFileUtil.java +++ b/src/main/java/net/openhft/chronicle/testframework/mappedfiles/MappedFileUtil.java @@ -9,7 +9,9 @@ import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,7 +56,9 @@ public static Set getAllMappedFiles() { final Set fileList = new HashSet<>(); if (Files.exists(PROC_SELF_MAPS) && Files.isReadable(PROC_SELF_MAPS)) { - try (final BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(PROC_SELF_MAPS)))) { + try (InputStream inputStream = Files.newInputStream(PROC_SELF_MAPS); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(inputStreamReader)) { processProcSelfMaps(fileList, reader); } catch (IOException e) { throw new IllegalStateException("Getting mapped files failed", e); diff --git a/src/main/java/net/openhft/chronicle/testframework/process/JavaProcessBuilder.java b/src/main/java/net/openhft/chronicle/testframework/process/JavaProcessBuilder.java index c6fa0d66..9c4135d8 100644 --- a/src/main/java/net/openhft/chronicle/testframework/process/JavaProcessBuilder.java +++ b/src/main/java/net/openhft/chronicle/testframework/process/JavaProcessBuilder.java @@ -85,7 +85,7 @@ static JavaProcessBuilder create(@NotNull final Class mainClass) { * streams. ProcessBuilder.inheritIO() did not play nicely with the Maven * failsafe plugin. *

- * https://maven.apache.org/surefire/maven-failsafe-plugin/faq.html#corruptedstream + * ... */ static void printProcessOutput(String processName, Process process) { requireNonNull(processName); diff --git a/src/test/java/net/openhft/chronicle/core/Bootstrap.java b/src/test/java/net/openhft/chronicle/core/Bootstrap.java index 5b002f26..cbed52bb 100644 --- a/src/test/java/net/openhft/chronicle/core/Bootstrap.java +++ b/src/test/java/net/openhft/chronicle/core/Bootstrap.java @@ -7,6 +7,7 @@ * Exists purely to mock core Bootstrap inside tests for CodeStructureVerifierTest. */ public class Bootstrap { + @SuppressWarnings("EmptyMethod") public static void bootstrap() { // Intentional no-op } diff --git a/src/test/java/net/openhft/chronicle/testframework/SeriesTest.java b/src/test/java/net/openhft/chronicle/testframework/SeriesTest.java index 77521ce5..060a4e95 100644 --- a/src/test/java/net/openhft/chronicle/testframework/SeriesTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/SeriesTest.java @@ -48,5 +48,4 @@ private static void test(final long[] expected, .toArray(); assertArrayEquals(expected, actual); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/codestructure/Bootstrap.java b/src/test/java/net/openhft/chronicle/testframework/codestructure/Bootstrap.java index 138811f4..1cf6bea0 100644 --- a/src/test/java/net/openhft/chronicle/testframework/codestructure/Bootstrap.java +++ b/src/test/java/net/openhft/chronicle/testframework/codestructure/Bootstrap.java @@ -7,6 +7,7 @@ @VisibleForTesting class Bootstrap { + @SuppressWarnings("EmptyMethod") public static void bootstrap() { // Intentional no-op } diff --git a/src/test/java/net/openhft/chronicle/testframework/codestructure/CodeStructureVerifierTest.java b/src/test/java/net/openhft/chronicle/testframework/codestructure/CodeStructureVerifierTest.java index cab4e754..8c9da4f2 100644 --- a/src/test/java/net/openhft/chronicle/testframework/codestructure/CodeStructureVerifierTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/codestructure/CodeStructureVerifierTest.java @@ -117,5 +117,4 @@ void nonCompliantDtoAlias() { } } - } \ No newline at end of file diff --git a/src/test/java/net/openhft/chronicle/testframework/codestructure/DelegatesToInternal.java b/src/test/java/net/openhft/chronicle/testframework/codestructure/DelegatesToInternal.java index 1f7eeadc..3c71b375 100644 --- a/src/test/java/net/openhft/chronicle/testframework/codestructure/DelegatesToInternal.java +++ b/src/test/java/net/openhft/chronicle/testframework/codestructure/DelegatesToInternal.java @@ -7,6 +7,7 @@ class DelegatesToInternal { + @SuppressWarnings({"unused", "InstantiationOfUtilityClass"}) private final ExampleInternal delegate = new ExampleInternal(); } diff --git a/src/test/java/net/openhft/chronicle/testframework/codestructure/DtoAlias.java b/src/test/java/net/openhft/chronicle/testframework/codestructure/DtoAlias.java index 14f2c23b..f39bc1e4 100644 --- a/src/test/java/net/openhft/chronicle/testframework/codestructure/DtoAlias.java +++ b/src/test/java/net/openhft/chronicle/testframework/codestructure/DtoAlias.java @@ -10,6 +10,8 @@ class DtoAlias { net.openhft.chronicle.core.Bootstrap.bootstrap(); } + @SuppressWarnings("EmptyMethod") public static void init() { + // Intentional no-op } } diff --git a/src/test/java/net/openhft/chronicle/testframework/codestructure/internal/ExampleInternal.java b/src/test/java/net/openhft/chronicle/testframework/codestructure/internal/ExampleInternal.java index 47885c3e..56ef7016 100644 --- a/src/test/java/net/openhft/chronicle/testframework/codestructure/internal/ExampleInternal.java +++ b/src/test/java/net/openhft/chronicle/testframework/codestructure/internal/ExampleInternal.java @@ -4,7 +4,8 @@ package net.openhft.chronicle.testframework.codestructure.internal; public class ExampleInternal { + @SuppressWarnings({"unused", "EmptyMethod"}) public static void example() { - + // Intentional no-op } } diff --git a/src/test/java/net/openhft/chronicle/testframework/dto/DtoTesterDemoTest.java b/src/test/java/net/openhft/chronicle/testframework/dto/DtoTesterDemoTest.java index 1d1ee4c2..68a55cc0 100644 --- a/src/test/java/net/openhft/chronicle/testframework/dto/DtoTesterDemoTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/dto/DtoTesterDemoTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.Test; +import java.util.Objects; + import static net.openhft.chronicle.testframework.dto.DtoTester.MutatorType.MANDATORY; import static net.openhft.chronicle.testframework.dto.DtoTester.MutatorType.OPTIONAL; @@ -29,12 +31,7 @@ void demo() { .withResetter(MyDto::reset) // Setup validation rules - /* - .addValidationRule("name", MyDto::name, null) - */ - - // Assert the validation rules when all mandatory mutators have been invoked and with a - // combination of optional ones + // Assert the validation rules when all mandatory mutators have been invoked and with a combination of optional ones .withValidator(MyDto::validate) .build() @@ -101,7 +98,7 @@ public boolean equals(Object o) { MyDtoImpl myDto = (MyDtoImpl) o; if (shoeSize != myDto.shoeSize) return false; - return name != null ? name.equals(myDto.name) : myDto.name == null; + return Objects.equals(name, myDto.name); } @Override diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/CombPermDemoTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/CombPermDemoTest.java index 047f6abc..d822766c 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/CombPermDemoTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/CombPermDemoTest.java @@ -11,6 +11,7 @@ class CombPermDemoTest { + @SuppressWarnings("MappingBeforeCount") @Test void demo() { assertEquals(16, diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/CombinationDemoTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/CombinationDemoTest.java index 4acaa3d1..668cc956 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/CombinationDemoTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/CombinationDemoTest.java @@ -36,6 +36,7 @@ */ final class CombinationDemoTest { + @SuppressWarnings("MappingBeforeCount") @Test void print() { assertEquals(8, @@ -61,12 +62,15 @@ Stream demo() { private static class FaultTolerantBitSet { + @SuppressWarnings("EmptyMethod") void cosmicRayBit3() { } + @SuppressWarnings("EmptyMethod") void cosmicRayBit23() { } + @SuppressWarnings("EmptyMethod") void cosmicRayBit13() { } @@ -74,5 +78,4 @@ boolean isValid() { return true; } } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/DelegationBuilderTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/DelegationBuilderTest.java index 0a4da65f..89063087 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/DelegationBuilderTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/DelegationBuilderTest.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.testframework.internal; -import net.openhft.chronicle.testframework.Delegation; import org.junit.jupiter.api.Test; import java.util.Arrays; diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/ListDemoTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/ListDemoTest.java index 98829cde..49c32286 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/ListDemoTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/ListDemoTest.java @@ -87,6 +87,7 @@ Stream validateMany() { }); } + @SuppressWarnings("MappingBeforeCount") @Test void print() { assertEquals(10, Combination.of(CONSTRUCTORS) @@ -147,5 +148,4 @@ private Tuple toTuple(Set set) { final Iterator iterator = set.iterator(); return new Tuple<>(iterator.next(), iterator.next()); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/PermutationDemoTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/PermutationDemoTest.java index bb45a2c8..66e41684 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/PermutationDemoTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/PermutationDemoTest.java @@ -32,6 +32,7 @@ final class PermutationDemoTest { + @SuppressWarnings("MappingBeforeCount") @Test void print() { assertEquals(6, @@ -129,5 +130,4 @@ public String toString() { '}'; } } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/PermutationTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/PermutationTest.java index 34a4c332..fb0ce48c 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/PermutationTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/PermutationTest.java @@ -40,24 +40,18 @@ Stream factorial() { return IntStream.range(0, 10) .mapToObj(i -> DynamicTest.dynamicTest("factorial(" + i + ")", - () -> { - assertEquals(Permutation.factorial(i), fac(i)); - }) + () -> assertEquals(Permutation.factorial(i), fac(i))) ); } @Test void factorialTooLarge() { - assertThrows(IllegalArgumentException.class, () -> { - Permutation.factorial(21); - }); + assertThrows(IllegalArgumentException.class, () -> Permutation.factorial(21)); } @Test void factorialNegative() { - assertThrows(IllegalArgumentException.class, () -> { - Permutation.factorial(-1); - }); + assertThrows(IllegalArgumentException.class, () -> Permutation.factorial(-1)); } private static final List LIST = Arrays.asList(1,2,3); @@ -70,7 +64,6 @@ void factorialNegative() { 3, 1, 2 3, 2, 1 */ - @Test void permutation0() { assertEquals(Arrays.asList(1, 2, 3), Permutation.permutation(0, LIST)); @@ -146,5 +139,4 @@ private long fac(int i) { if (i == 0) return 1; return i * fac(i - 1); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/ProductDemoTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/ProductDemoTest.java index 979497c0..6b5299f4 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/ProductDemoTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/ProductDemoTest.java @@ -33,6 +33,7 @@ final class ProductDemoTest { + @SuppressWarnings("MappingBeforeCount") @Test void print() { assertEquals(9, @@ -42,6 +43,7 @@ void print() { } // Exhaustively tests if various empty collections invariants holds + @SuppressWarnings("ReplaceInefficientStreamCount") @TestFactory Stream demo() { // Operations @@ -51,6 +53,7 @@ Stream demo() { c -> assertTrue(c.isEmpty(), c.getClass() + ".empty() was false"); final Consumer> size = c -> assertEquals(0, c.size(), c.getClass() + ".size() != 0"); + @SuppressWarnings("ReplaceInefficientStreamCount") final Consumer> streamCount = c -> assertEquals(0, c.stream().count(), c.getClass() + ".stream().count() != 0"); final List>> operations = Arrays.asList(empty, size, streamCount); @@ -61,5 +64,4 @@ Stream demo() { tuple -> tuple.second().accept(tuple.first()) ); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/ProductTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/ProductTest.java index a75538cf..8eded5be 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/ProductTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/ProductTest.java @@ -103,5 +103,4 @@ void product3Stream() { } assertEquals(expected, actual); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/VanillaFlakyTestRunnerTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/VanillaFlakyTestRunnerTest.java index f1ca246e..b5478e62 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/VanillaFlakyTestRunnerTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/VanillaFlakyTestRunnerTest.java @@ -72,6 +72,7 @@ void testUnchecked() { assertDoesNotThrow(runner::run); } + @SuppressWarnings("EmptyMethod") private void foo() { // Do nothing and throw nothing } @@ -115,5 +116,4 @@ public void run() throws IllegalStateException { throw new IllegalStateException("" + countDown--); } } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/VanillaNamedConsumerTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/VanillaNamedConsumerTest.java index 0d9b6528..d4b804c0 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/VanillaNamedConsumerTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/VanillaNamedConsumerTest.java @@ -36,5 +36,4 @@ void nullInConstructorConsumer() { void nullInConstructorName() { assertThrows(NullPointerException.class, () -> new VanillaNamedConsumer<>(v -> {}, null)); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/VanillaThrowingConsumerTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/VanillaThrowingConsumerTest.java index 26a71fb8..aee21eb1 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/VanillaThrowingConsumerTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/VanillaThrowingConsumerTest.java @@ -13,6 +13,7 @@ class VanillaThrowingConsumerTest { + @SuppressWarnings("ResultOfMethodCallIgnored") @Test void accept() { // Guaranteed to fail (Invalid file path) diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/Foo.java b/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/Foo.java index b18782b3..1c79f136 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/Foo.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/Foo.java @@ -21,5 +21,4 @@ public void x(int x) { protected int zero() { return 0; } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetricsBuilderTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetricsBuilderTest.java index 08a98384..d62e5d71 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetricsBuilderTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/apimetrics/StandardApiMetricsBuilderTest.java @@ -23,5 +23,4 @@ void enumTest() { .forEach(System.out::println); } - } diff --git a/src/test/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxyTest.java b/src/test/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxyTest.java index 105b3cdd..166a3a48 100644 --- a/src/test/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxyTest.java +++ b/src/test/java/net/openhft/chronicle/testframework/internal/network/proxy/TcpProxyTest.java @@ -19,8 +19,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import static net.openhft.chronicle.testframework.ExecutorServiceUtil.shutdownAndWaitForTermination; -import static net.openhft.chronicle.testframework.NetworkUtil.getAvailablePort; import static net.openhft.chronicle.testframework.ThreadUtil.pause; import static net.openhft.chronicle.testframework.Waiters.waitForCondition; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -28,7 +28,7 @@ @DisabledOnOs(value = OS.MAC, disabledReason = "MacOS loopback strangeness causes intermittent failures") class TcpProxyTest { - private static final Logger LOGGER = LoggerFactory.getLogger(TcpProxy.class); + private static final Logger LOGGER = LoggerFactory.getLogger(TcpProxyTest.class); private static final int TIMEOUT_MS = 3_000; private ExecutorService executorService; @@ -107,7 +107,7 @@ private boolean atEndOfStream(SocketChannel socketChannel) { } private void sendString(SocketChannel channel, String string) throws IOException { - final ByteBuffer helloBuffer = ByteBuffer.wrap(string.getBytes()); + final ByteBuffer helloBuffer = ByteBuffer.wrap(string.getBytes(ISO_8859_1)); channel.write(helloBuffer); } @@ -115,13 +115,13 @@ private String receiveString(SocketChannel channel) throws IOException { ByteBuffer recvBuf = ByteBuffer.allocate(128); channel.read(recvBuf); recvBuf.flip(); - return new String(recvBuf.array(), recvBuf.position(), recvBuf.remaining()); + return new String(recvBuf.array(), recvBuf.position(), recvBuf.remaining(), ISO_8859_1); } private void startServerAndProxyAnd(ServerAndProxyBody serverAndProxyConsumer) throws IOException { try (final ServerSocketChannel serverSocket = ServerSocketChannel.open().bind(new InetSocketAddress(0)); final TcpProxy tcpProxy = new TcpProxy(0, (InetSocketAddress) serverSocket.socket().getLocalSocketAddress(), executorService)) { - LOGGER.info("Server listening on " + serverSocket.socket().getLocalSocketAddress()); + LOGGER.info("Server listening on {}", serverSocket.socket().getLocalSocketAddress()); executorService.submit(tcpProxy); waitForCondition("TCP proxy didn't open", tcpProxy::isOpen, TIMEOUT_MS); serverSocket.configureBlocking(false); @@ -134,7 +134,7 @@ private void connectViaProxyAnd(ServerSocketChannel serverSocket, TcpProxy tcpPr waitForCondition("TCP proxy didn't open", tcpProxy::isOpen, TIMEOUT_MS); clientSocket.configureBlocking(false); final InetSocketAddress remote = tcpProxy.socketAddress(); - LOGGER.info("Client connecting to " + remote); + LOGGER.info("Client connecting to {}", remote); clientSocket.connect(new InetSocketAddress("localhost", remote.getPort())); long endTime = System.currentTimeMillis() + TIMEOUT_MS; SocketChannel connection = serverSocket.accept();