Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🧠 ♻️ 🧪 Refactor prolog predicates testing methodology #579

Merged
merged 7 commits into from
Feb 29, 2024

Conversation

ccamel
Copy link
Member

@ccamel ccamel commented Feb 28, 2024

This PR addresses the main concern outlined in ticket #498 regarding improving the test methodology for predicates in the logic module.

Initial idea carried by #498

The proposed change was to switch to purely Prolog-based tests. This is to:

  • Reduce the complexity of writing and debugging tests,
  • Gain expressiveness by focusing on the core of the test, the evaluation of Prolog predicates and their solutions,
  • Allow a "test as documentation" approach, thereby using tests to enrich the documentation of predicates on our technical website.

However, this approach, upon analysis, proves to be quite delicate. Firstly, because it requires a Prolog interpretation layer to build the tests, with mechanisms for asserting solutions. And secondly, because it makes expressing the context in which the tests are performed challenging (such as setting a wallet address with a certain number of tokens in the bank module).

Implementation: Gherkin

We're opting for a test methodology approach based on Gherkin. This is a textual, behavior-oriented approach that is human oriented, simple to implement, highly extensible.

What's changed

This PR introduces a Gherkin test suite that allows for the execution of predicate tests (called features).

To pave the way, I've transposed the unit tests from smartystreets/goconvey to Gherkin for the predicate bech32_address/2.

The test is now carried out at the highest level, i.e. as a client of the logic module, which allows for very good control of the module's interface contract, as well as a better understanding of the test from a consumer point of view.

For instance:

Feature: bech32_address/2
  This feature is to test the bech32_address/2 predicate.

  @great_for_documentation
  Scenario: Decode Bech32 Address into its Address Pair representation.
    This scenario demonstrates how to parse a provided bech32 address string into its `Address` pair representation.
    An `Address` is a compound term `-` with two arguments, the first being the human-readable part (Hrp) and the second
    being the numeric address as a list of integers ranging from 0 to 255 representing the bytes of the address in
    base 64.

    Given the query:
      """ prolog
      bech32_address(Address, 'okp415wn30a9z4uc692s0kkx5fp5d4qfr3ac7sj9dqn').
      """
    When the query is run
    Then the answer we get is:
      """ yaml
      has_more: false
      variables: ["Address"]
      results:
      - substitutions:
        - variable: Address
          expression: "okp4-[163,167,23,244,162,175,49,162,170,15,181,141,68,134,141,168,18,56,247,30]"
      """

Moreover, since the tests are described by a textual document and have significant documentary and exemplary value, I've modified the predicate documentation generator to allow the inclusion of test scenarios in the documentation. As not all scenarios are equally valuable, only those tagged @great_for_documentation are included, allowing for precise control over what is exposed.

Next steps

The effort needs to be extended to all other predicates, but it's a lengthy task. And we might consider using this new approach primarily for newly implemented predicates.

Summary by CodeRabbit

  • New Features
    • Expanded the functionality of the bech32_address/2 predicate for decoding and encoding bech32 addresses, including error handling for incorrect formats.
    • Introduced a feature file bech32_address_2.feature for testing the bech32_address/2 predicate with various scenarios.
  • Documentation
    • Updated and generated new documentation for predicates, including scenarios and features.
  • Refactor
    • Updated generate_predicates_doc.go script with new imports, variable names, and functions for better documentation generation.
    • Improved the Bech32Address predicate with a clearer function signature and focused functionality.
  • Chores
    • Added .editorconfig settings for .feature files to standardize indent size.
  • Tests
    • Added features_test.go for behavior-driven development testing of the logic module's features.

Copy link
Contributor

coderabbitai bot commented Feb 28, 2024

Walkthrough

This update enhances and expands the functionality and documentation of predicates, particularly focusing on the bech32_address/2 predicate. It introduces a new testing approach for the logic module using behavior-driven development and updates documentation generation scripts. The changes streamline the testing process and improve the handling and documentation of predicates, making the system more robust and user-friendly.

Changes

File(s) Change Summary
.editorconfig Added .feature extension configuration with indent_size set to 2.
docs/predicate/bech32_address_2.md
x/logic/keeper/features/bech32_address_2.feature
Expanded bech32_address/2 predicate functionality and added related feature documentation and tests.
scripts/generate_predicates_doc.go
scripts/templates/func.go.txt
Updated documentation generation for predicates with new imports, functions, and template file extensions.
x/logic/keeper/features_test.go Introduced behavior-driven development testing for the logic module.
x/logic/predicate/address.go Updated Bech32Address predicate functionality for clearer conversion between bech32 and base64.

Related issues

  • okp4/okp4d#498: The refactoring and enhancement of testing approaches for predicates in this PR could align with the objectives to transition core testing logic to a more maintainable process, as sought in the issue.

🐰✨

In a world of code and endless test,
A rabbit hopped, refusing to rest.
With every leap and bound, it sought
To fix, improve, and sort.
Through bech32 and predicates galore,
It left the codebase better than before.
🌟📜🚀

🐰✨

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

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>.
    • Generate unit-tests for this file.
  • 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 generate unit tests for this file.
    • @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 generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

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 as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • 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/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@ccamel ccamel self-assigned this Feb 28, 2024
@ccamel ccamel marked this pull request as ready for review February 28, 2024 20:27
Copy link
Contributor

@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.

Review Status

Actionable comments generated: 5

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 16e42f8 and 939b214.
Files ignored due to path filters (2)
  • go.mod is excluded by: !**/*.mod
  • go.sum is excluded by: !**/*.sum
Files selected for processing (7)
  • .editorconfig (1 hunks)
  • docs/predicate/bech32_address_2.md (2 hunks)
  • scripts/generate_predicates_doc.go (5 hunks)
  • scripts/templates/func.go.txt (1 hunks)
  • x/logic/keeper/features/bech32_address_2.feature (1 hunks)
  • x/logic/keeper/features_test.go (1 hunks)
  • x/logic/predicate/address.go (1 hunks)
Files skipped from review due to trivial changes (2)
  • .editorconfig
  • scripts/templates/func.go.txt
Additional comments: 37
x/logic/predicate/address.go (5)
  • 14-17: The updated documentation provides a clearer signature definition for the Bech32Address predicate. This change enhances the readability and understanding of the function's purpose and usage.
  • 16-17: The signature documentation now explicitly states the determinism of the bech32_address predicate with both input-output and output-input modes. This clarification is beneficial for users to understand the function's behavior in different scenarios.
  • 16-17: The documentation now includes a more detailed explanation of the parameters Address and Bech32, including the range of values for the base64 encoded address string. This improvement enhances the clarity and usability of the documentation.
  • 16-17: The inclusion of references to the bech32 and base64 encoding standards in the documentation is a good practice, providing users with resources for further reading and understanding.
  • 16-17: The function's implementation appears to correctly handle the conversion between bech32 encoded strings and base64 bytes, including error handling for invalid encodings. This ensures robustness and reliability of the predicate.
scripts/generate_predicates_doc.go (7)
  • 9-18: The addition of imports for handling file paths, regular expressions, Gherkin parsing, and dedentation is necessary for the new functionality introduced in this script. These imports enable the script to process Gherkin feature files and incorporate them into the documentation.
  • 29-31: Renaming the constants predicatePath and outputPath to predicatesPath and featuresPath respectively, improves the clarity and accuracy of these identifiers, reflecting their actual usage in the script.
  • 34-34: The introduction of the featureRegEx variable, a regular expression to match .feature files, is a practical approach to filter and process only the relevant files for documentation generation.
  • 58-62: The loadFeatures function call within generatePredicateDocumentation to load Gherkin features into the global context is a significant enhancement. This change allows the script to include detailed scenario-based documentation for predicates, improving the documentation's usefulness and readability.
  • 96-101: Updating the template file extensions from .gotxt to .go.txt and adding new template functions dedent and tagged are necessary changes to support the inclusion of Gherkin features in the documentation. These updates enhance the flexibility and capability of the documentation generation process.
  • 122-123: The addition of the dedent and tagged template functions provides valuable tools for processing and filtering the content of Gherkin features. These functions enable the script to present the documentation in a more readable and organized manner.
  • 162-166: The tagged function, which filters scenarios based on tags, is a useful feature for selectively including scenarios in the documentation. This allows for greater control over the content and presentation of the documentation.
x/logic/keeper/features_test.go (5)
  • 34-47: The setup of the godog test suite with scenario initialization and options configuration is correctly implemented. Specifying the pretty format and the features path ensures that the test output is readable and that the correct feature files are used for testing.
  • 49-67: The definition of the testCase struct and the context handling functions (testCaseToContext and testCaseFromContext) are well-implemented. These constructs provide a clean and efficient way to pass test case data through the context during scenario execution.
  • 69-100: The step definitions (givenTheProgram, givenTheQuery, whenTheQueryIsRun, theAnswerWeGetIs) are correctly implemented to match the Gherkin steps. These functions effectively translate the Gherkin steps into actions and assertions within the test environment.
  • 102-123: The custom assert function provides a structured way to perform assertions and generate detailed error messages in case of failures. This enhances the readability and debuggability of test failures.
  • 125-170: The initializeScenario function, which sets up the test context and registers the Gherkin step definitions, is well-structured. It ensures that each scenario starts with a clean state and that all necessary dependencies are correctly initialized.
docs/predicate/bech32_address_2.md (7)
  • 12-17: The updated signature documentation for the bech32_address/2 predicate is clear and concise, providing a solid foundation for understanding the predicate's functionality.
  • 26-51: The scenario for decoding a Bech32 address into its address pair representation is well-explained and demonstrates the predicate's capability effectively. The step-by-step explanation and the example query and result enhance the documentation's educational value.
  • 53-79: The scenario for decoding the HRP and address from a Bech32 address is another excellent example of the predicate's functionality. The clear presentation of the query and the expected result helps users understand how to use the predicate for this specific task.
  • 81-104: The scenario for extracting the address only for an OKP4 Bech32 address is a practical example that highlights the predicate's flexibility in handling different protocols. This scenario adds value by showing a specific use case relevant to the OKP4 protocol.
  • 106-128: The scenario for encoding an address pair into a Bech32 address is crucial for demonstrating the predicate's bidirectional functionality. The detailed steps and the clear presentation of the expected result make this scenario an essential part of the documentation.
  • 130-155: The scenario for checking if a Bech32 address is part of the OKP4 protocol using a custom Prolog program is an advanced example that showcases the predicate's integration with other Prolog constructs. This scenario enhances the documentation by demonstrating a more complex use case.
  • 157-179: The error handling scenarios for incorrect Bech32 address formats and types are important for users to understand the predicate's behavior in case of invalid inputs. These scenarios are well-documented and provide valuable information on error handling.
x/logic/keeper/features/bech32_address_2.feature (13)
  • 1-5: The feature description is clear and concise, providing a good overview of the purpose of the feature file. The title Feature: bech32_address/2 effectively communicates the focus of the tests.
  • 4-24: The scenario "Decode Bech32 Address into its Address Pair representation" is well-structured and demonstrates the decoding functionality clearly. The use of Gherkin syntax is correct, and the scenario is tagged with @great_for_documentation, which is appropriate given its explanatory nature. The description and steps are clear, making the test easy to understand.
  • 25-46: The scenario "Decode Hrp and Address from a bech32 address" is another example of a well-written test case. It clearly illustrates how to decode both the human-readable part and the numeric address from a bech32 address. The scenario is appropriately tagged for documentation and follows Gherkin syntax correctly.
  • 47-65: The scenario "Extract Address only for OKP4 bech32 address" is specific to the okp4 protocol, which is a good addition for testing protocol-specific functionality. The scenario is clear and concise, effectively demonstrating how to extract the address component. The tagging and syntax are correctly applied.
  • 66-82: The scenario "Encode Address Pair into Bech32 Address" effectively demonstrates the encoding process. It's a good counterpart to the decoding scenarios, providing a comprehensive test coverage for the bech32_address/2 predicate. The scenario is well-documented and follows the Gherkin syntax accurately.
  • 134-149: The scenario "Decode HRP from a bech32 address" is another well-structured test case that focuses on decoding the human-readable part from a bech32 address. The scenario is clear and follows the Gherkin syntax correctly. It's tagged appropriately for documentation purposes.
  • 152-167: The scenario "Error on Incorrect Bech32 Address format" effectively demonstrates error handling for an incorrect bech32 address format. The detailed error message in the results section is helpful for understanding the expected system response. This scenario is a good example of testing error conditions and is appropriately tagged for documentation.
  • 170-185: The scenario "Error on Incorrect Bech32 Address type" is similar to the previous one but focuses on type errors. The scenario is clear and provides a detailed error message, which is valuable for documentation and understanding the predicate's behavior in error conditions.
  • 188-202: The scenario "Error on Incorrect Hrp type" tests for type errors related to the human-readable part. It's another important test case for error handling, with a clear structure and detailed error message. The scenario is correctly tagged and follows the Gherkin syntax.
  • 204-219: The scenario "Error on Incorrect Hrp type (2)" is a continuation of testing for type errors with different inputs. It maintains the consistency of testing error conditions and provides a clear, detailed error message. The scenario is well-documented and follows the Gherkin syntax accurately.
  • 222-236: The scenario "Error on Incorrect Address type" focuses on type errors related to the address component. It's another valuable test case for error handling, with a clear structure and detailed error message. The scenario is correctly tagged for documentation purposes.
  • 238-253: The scenario "Error on Incorrect Address type (2)" continues the theme of testing for type errors with different inputs. It provides a clear, detailed error message, which is helpful for understanding the expected behavior in error conditions. The scenario is well-documented and follows the Gherkin syntax.
  • 255-270: The scenario "Error on Incorrect Address type (3)" tests for type errors with yet another input variation. It maintains the consistency of testing error conditions and provides a clear, detailed error message. The scenario is correctly tagged for documentation purposes.

@ccamel ccamel requested a review from amimart February 28, 2024 21:00
Copy link
Member

@amimart amimart left a comment

Choose a reason for hiding this comment

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

Ahah excellent! That's sexy I like that 😉

@ccamel ccamel changed the title ♻️ Refactor prolog predicates testing methodology ♻️ 🧪 Refactor prolog predicates testing methodology Feb 29, 2024
@ccamel ccamel changed the title ♻️ 🧪 Refactor prolog predicates testing methodology 🧠 ♻️ 🧪 Refactor prolog predicates testing methodology Feb 29, 2024
@ccamel ccamel merged commit acac2b0 into main Feb 29, 2024
19 checks passed
@ccamel ccamel deleted the test/improvements branch February 29, 2024 11:49
@bot-anik
Copy link
Member

🎉 This PR is included in version 7.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants