Claude skill for my OCaml metadata management
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

initial import

+769
+17
.gitignore
··· 1 + # OCaml build artifacts 2 + _build/ 3 + *.install 4 + *.merlin 5 + 6 + # Third-party sources (fetch locally with opam source) 7 + third_party/ 8 + 9 + # Editor and OS files 10 + .DS_Store 11 + *.swp 12 + *~ 13 + .vscode/ 14 + .idea/ 15 + 16 + # Opam local switch 17 + _opam/
+1
.ocamlformat
··· 1 + version=0.28.1
+53
.tangled/workflows/build.yml
··· 1 + when: 2 + - event: ["push", "pull_request"] 3 + branch: ["main"] 4 + 5 + engine: nixery 6 + 7 + dependencies: 8 + nixpkgs: 9 + - shell 10 + - stdenv 11 + - findutils 12 + - binutils 13 + - libunwind 14 + - ncurses 15 + - opam 16 + - git 17 + - gawk 18 + - gnupatch 19 + - gnum4 20 + - gnumake 21 + - gnutar 22 + - gnused 23 + - gnugrep 24 + - diffutils 25 + - gzip 26 + - bzip2 27 + - gcc 28 + - ocaml 29 + - pkg-config 30 + 31 + steps: 32 + - name: opam 33 + command: | 34 + opam init --disable-sandboxing -a -y 35 + - name: repo 36 + command: | 37 + opam repo add aoah https://tangled.org/anil.recoil.org/aoah-opam-repo.git 38 + - name: switch 39 + command: | 40 + opam install . --confirm-level=unsafe-yes --deps-only 41 + - name: build 42 + command: | 43 + opam exec -- dune build 44 + - name: switch-test 45 + command: | 46 + opam install . --confirm-level=unsafe-yes --deps-only --with-test 47 + - name: test 48 + command: | 49 + opam exec -- dune runtest --verbose 50 + - name: doc 51 + command: | 52 + opam install -y odoc 53 + opam exec -- dune build @doc
+15
LICENSE.md
··· 1 + ISC License 2 + 3 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org> 4 + 5 + Permission to use, copy, modify, and distribute this software for any 6 + purpose with or without fee is hereby granted, provided that the above 7 + copyright notice and this permission notice appear in all copies. 8 + 9 + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+46
README.md
··· 1 + # project-name - Brief Project Title 2 + 3 + Brief introduction paragraph explaining what this library/tool does and its main purpose. 4 + 5 + ## Key Features 6 + 7 + - Feature 1: Description 8 + - Feature 2: Description 9 + - Feature 3: Description 10 + 11 + ## Usage 12 + 13 + ```ocaml 14 + (* Basic usage example *) 15 + let example () = 16 + (* Show simple, practical usage *) 17 + () 18 + ``` 19 + 20 + For more advanced usage: 21 + 22 + ```ocaml 23 + (* More complex example *) 24 + let advanced_example () = 25 + (* Show additional features *) 26 + () 27 + ``` 28 + 29 + ## Installation 30 + 31 + ``` 32 + opam install project-name 33 + ``` 34 + 35 + ## Documentation 36 + 37 + API documentation is available at [project URL] or via: 38 + 39 + ``` 40 + opam install project-name 41 + odig doc project-name 42 + ``` 43 + 44 + ## License 45 + 46 + ISC
+259
SKILL.md
··· 1 + --- 2 + name: ocaml-metadata 3 + description: Standards for OCaml project metadata files. Use when initialising a new OCaml library/module, preparing for opam release, setting up testing infrastructure, or searching the OCaml ecosystem for dependencies. Not for normal code edits. 4 + license: ISC 5 + --- 6 + 7 + # OCaml Project Metadata Standards 8 + 9 + ## When to Use This Skill 10 + 11 + Invoke this skill when: 12 + 13 + 1. **Initializing a new OCaml project** - Setting up dune-project, LICENSE, README, CI, etc. 14 + 2. **Preparing for opam release** - Ensuring all metadata is correct for publication 15 + 3. **Setting up testing infrastructure** - Especially for Eio-based libraries that need mock testing 16 + 4. **Searching the OCaml ecosystem** - Finding and fetching dependency sources for reference 17 + 5. **Adding third-party source references** - Using `opam source` to study library implementations 18 + 19 + **Do not use for:** 20 + - Regular code edits or bug fixes 21 + - Simple function additions 22 + - Refactoring existing code 23 + 24 + ## License Header 25 + 26 + All projects use the ISC license (see LICENSE.md in this directory). 27 + 28 + Every OCaml source file must start with this license header: 29 + 30 + ```ocaml 31 + (*--------------------------------------------------------------------------- 32 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 33 + SPDX-License-Identifier: ISC 34 + ---------------------------------------------------------------------------*) 35 + ``` 36 + 37 + ## Build System (Dune) 38 + 39 + Use Dune for builds with automatic opam file generation enabled. 40 + 41 + **Required file:** `dune-project` 42 + - See the `dune-project` file in this skill directory for a reference template 43 + - Update project name, synopsis, description, and dependencies as needed 44 + - Always set `(generate_opam_files true)` 45 + - Use `(maintenance_intent "(latest)")` for actively maintained projects 46 + - **Do not add a `(version ...)` field** - this will be added at release time 47 + - **For Tangled projects, do not use `(source ...)` stanza** - if the project URL is tangled.org or git remote is not github.com (e.g., git.recoil.org), omit the source field entirely 48 + - You can determine the project SSH url from the git remote origin; if it 49 + is not a github.com URL, then it's probably tangled. For Tangled projects, follow the specific URL schema 50 + shown in the same dune-project file here, with URLs going to https://tangled.org/ 51 + 52 + **Required file:** `dune` (root) 53 + - See the `dune` file in this skill directory for a reference template 54 + - Include `(data_only_dirs third_party)` to ignore fetched dependency sources 55 + - Add other project-wide Dune configuration as needed 56 + 57 + ## Version Control 58 + 59 + **Required file:** `.gitignore` 60 + - See the `.gitignore` file in this skill directory for a reference template 61 + - Always include `third_party/` to exclude fetched dependency sources 62 + - Include standard OCaml build artifacts (`_build/`, `*.install`, etc.) 63 + - Include editor and OS-specific files (`.DS_Store`, `.vscode/`, etc.) 64 + 65 + ## Code Formatting 66 + 67 + Use OCamlFormat with default styling. 68 + 69 + **Required file:** `.ocamlformat` 70 + - Copy the `.ocamlformat` file from this skill directory 71 + - Current version: 0.28.1 72 + 73 + ## Testing 74 + 75 + **Reference:** See `TESTS.md` in this skill directory for detailed testing strategies. 76 + 77 + **Key points:** 78 + - Use Alcotest for test framework 79 + - **For Eio-based libraries:** Use Eio mock infrastructure (`Eio_mock`) instead of real I/O 80 + - Fetch dependency sources (e.g., eio) to understand mock APIs: see `SOURCES.md` 81 + - Prefer unit tests with mocks over integration tests 82 + - Test edge cases by injecting errors through mocks 83 + 84 + **Test directory structure:** 85 + ``` 86 + test/ 87 + ├── dune # Test configuration 88 + ├── test_mylib.ml # Unit tests (with mocks) 89 + └── test_integration.ml # Integration tests (minimal) 90 + ``` 91 + 92 + Add test dependencies to `dune-project`: 93 + ```lisp 94 + (depends 95 + ; ... 96 + (alcotest (and :with-test (>= 1.7.0))) 97 + (eio_main :with-test) ; if using Eio 98 + ) 99 + ``` 100 + 101 + ## Third-Party Sources 102 + 103 + **Reference:** See `SOURCES.md` in this skill directory for complete workflow. 104 + 105 + When developing, you may want to fetch dependency sources for reference: 106 + 107 + ```bash 108 + mkdir -p third_party 109 + cd third_party 110 + opam source <package-name> 111 + cd .. 112 + ``` 113 + 114 + **Required setup:** 115 + - Add `(data_only_dirs third_party)` to root `dune` file 116 + - Add `third_party/` to `.gitignore` 117 + - Generate `third_party/llms.txt` summary for discoverability 118 + 119 + This is especially useful for: 120 + - Understanding Eio mock APIs for testing 121 + - Studying implementation patterns 122 + - Referencing complex APIs 123 + 124 + ## Continuous Integration 125 + 126 + Use Tangled.org for CI. 127 + 128 + **Required file:** `.tangled/workflows/build.yml` 129 + - Copy from `.tangled/workflows/build.yml` in this skill directory if it doesn't exist 130 + - The default workflow includes: opam init, aoah-opam-repo overlay addition, dependency installation, build, test, and documentation generation 131 + - The workflow automatically adds the aoah-opam-repo overlay for development dependencies 132 + - If the project has special test requirements beyond standard opam tests, document them in the README and update build.yml accordingly 133 + 134 + ## Documentation 135 + 136 + **Required file:** `README.md` 137 + - See the `README.md` file in this skill directory for a reference template 138 + - Include: project title, brief description, key features, usage examples, installation instructions, and license 139 + - Keep it concise but informative 140 + - Use code examples to show practical usage 141 + - Update the template with project-specific information 142 + 143 + **Documentation builds (`dune build @doc`):** 144 + - When building documentation locally, warnings about unresolved references to third-party libraries (including standard library modules like `Random`, `String`, etc.) are **expected and OK** 145 + - These warnings appear because dune doesn't have access to external library documentation during local builds 146 + - Example warning: `Warning: Failed to resolve reference unresolvedroot(Random).float` 147 + - These references will be properly resolved when the package is built on OCaml.org's documentation infrastructure, which has access to all dependencies 148 + - **Do not attempt to fix these warnings** by removing or modifying the cross-references in documentation comments 149 + 150 + ## Opam Overlay Repository 151 + 152 + When developing packages that need to be available for CI before official release, add them to the overlay opam repository at `~/src/git/knot/aoah-opam-repo`. 153 + 154 + ### Adding Dev Packages to Overlay 155 + 156 + **Location:** `~/src/git/knot/aoah-opam-repo` 157 + 158 + **Structure:** Follow standard opam repository layout: 159 + ``` 160 + packages/ 161 + ├── package-name/ 162 + │ └── package-name.dev/ 163 + │ └── opam 164 + ``` 165 + 166 + **Version:** Always use `.dev` as the version suffix for development packages. 167 + 168 + ### Workflow for Adding a Package 169 + 170 + 1. **Read the source opam files** from the development repository to get metadata 171 + 2. **Create package directory structure:** 172 + ```bash 173 + mkdir -p ~/src/git/knot/aoah-opam-repo/packages/<package-name>/<package-name>.dev 174 + ``` 175 + 176 + 3. **Create the opam file** at `packages/<package-name>/<package-name>.dev/opam`: 177 + - Copy all metadata from the source opam file (synopsis, description, maintainer, authors, license, dependencies, build instructions) 178 + - Add `dev-repo` field pointing to the git repository 179 + - Add `url` stanza with git source and branch: 180 + ``` 181 + url { 182 + src: "git+https://tangled.org/@anil.recoil.org/<repo-name>.git#main" 183 + } 184 + ``` 185 + - For packages from the same repository (e.g., `yamlrw`, `yamlrw-eio`, `yamlrw-unix`): 186 + - Use `{= version}` for same-repo dependencies (e.g., `"yamlrw" {= version}`) 187 + - All point to the same git repository URL 188 + 189 + 4. **Handle multi-package repositories:** 190 + - If a repository generates multiple opam files (e.g., `yamlrw.opam`, `yamlrw-eio.opam`), create separate package directories for each 191 + - Each package gets its own `packages/<name>/<name>.dev/opam` entry 192 + - All packages from the same repo share the same `url.src` value 193 + 194 + ### Example: Adding yamlrw Packages 195 + 196 + For a repository with multiple packages (`yamlrw.opam`, `yamlrw-eio.opam`, `yamlrw-unix.opam`): 197 + 198 + ```bash 199 + # Create directory structure 200 + cd ~/src/git/knot/aoah-opam-repo 201 + mkdir -p packages/yamlrw/yamlrw.dev 202 + mkdir -p packages/yamlrw-eio/yamlrw-eio.dev 203 + mkdir -p packages/yamlrw-unix/yamlrw-unix.dev 204 + 205 + # Each opam file includes: 206 + # - Original metadata from source opam file 207 + # - dev-repo: "git+https://tangled.org/@anil.recoil.org/ocaml-yamlrw.git" 208 + # - url { src: "git+https://tangled.org/@anil.recoil.org/ocaml-yamlrw.git#main" } 209 + # - For yamlrw-eio and yamlrw-unix: "yamlrw" {= version} dependency 210 + ``` 211 + 212 + ### Using the Overlay Repository 213 + 214 + Add the overlay to your opam configuration: 215 + ```bash 216 + opam repository add aoah-dev ~/src/git/knot/aoah-opam-repo 217 + ``` 218 + 219 + This makes `.dev` versions available for installation: 220 + ```bash 221 + opam install bytesrw-eio.dev 222 + opam install yamlrw.dev yamlrw-eio.dev 223 + ``` 224 + 225 + ### Notes 226 + 227 + - Always use HTTPS URLs for `dev-repo` and `url.src` fields (e.g., `https://tangled.org/...`) 228 + - Track the `main` branch by default unless specified otherwise 229 + - Preserve all original metadata and dependencies from source opam files 230 + - Use `{= version}` for intra-repository dependencies to ensure version consistency 231 + 232 + ## File Checklist for New Projects 233 + 234 + When initializing a new OCaml project, ensure these files exist: 235 + 236 + **Essential files:** 237 + - [ ] `README.md` - Project documentation and usage examples 238 + - [ ] `dune-project` - Build configuration with opam file generation 239 + - [ ] `dune` (root) - With `(data_only_dirs third_party)` if using third-party sources 240 + - [ ] `.ocamlformat` - Code formatting configuration 241 + - [ ] `.gitignore` - Should include `third_party/` if fetching sources 242 + - [ ] `LICENSE.md` - ISC license 243 + - [ ] `.tangled/workflows/build.yml` - CI configuration 244 + - [ ] Source files with proper license headers 245 + 246 + **Test files:** 247 + - [ ] `test/dune` - Test executable configuration 248 + - [ ] `test/test_*.ml` - Test files (prefer mocks for Eio-based code) 249 + 250 + **Optional (for development):** 251 + - [ ] `third_party/` - Fetched dependency sources (not committed to git) 252 + - [ ] `third_party/llms.txt` - Summary of available third-party sources 253 + 254 + **For development packages:** 255 + - [ ] Add `.dev` package to `~/src/git/knot/aoah-opam-repo` overlay repository 256 + 257 + **Reference documentation in this skill:** 258 + - `TESTS.md` - Detailed testing strategies and Eio mock usage 259 + - `SOURCES.md` - How to fetch and manage third-party sources
+118
SOURCES.md
··· 1 + # Fetching Third-Party Sources for Analysis 2 + 3 + When developing a library, it's often helpful to have the source code of dependencies available for local analysis and reference. 4 + 5 + ## Setting Up Third-Party Sources 6 + 7 + ### 1. Search for Packages 8 + 9 + Find packages using opam search: 10 + 11 + ```bash 12 + opam search <package-name> 13 + ``` 14 + 15 + ### 2. Fetch Sources into third_party/ 16 + 17 + Download package sources into a `third_party/` directory: 18 + 19 + ```bash 20 + mkdir -p third_party 21 + cd third_party && opam source <package-name> && cd .. 22 + ``` 23 + 24 + **IMPORTANT**: Use `&&` to chain commands in a single bash call, or use separate sequential calls to avoid nested directories. The command above will create a directory like `third_party/<package-name>.<version>/` with the full source code. 25 + 26 + After running `opam source`, the package will be extracted to `third_party/<package-name>.<version>/` where you can read the source files directly. 27 + 28 + ### 3. Configure Dune to Ignore third_party/ 29 + 30 + Add to your root `dune` file (or create one if it doesn't exist): 31 + 32 + ```lisp 33 + (data_only_dirs third_party) 34 + ``` 35 + 36 + This tells Dune to ignore the `third_party/` directory during builds, treating it as data-only. 37 + 38 + ### 4. Add to .gitignore 39 + 40 + Add the following to your `.gitignore` file: 41 + 42 + ```gitignore 43 + # Third-party sources (fetch locally with opam source) 44 + third_party/ 45 + ``` 46 + 47 + ### 5. Generate llms.txt Summary 48 + 49 + After fetching sources, generate an `llms.txt` summary in the third_party directory for easier reference: 50 + 51 + ```bash 52 + # Create a summary of the library structure 53 + find third_party/<package-name>.<version> -name "*.mli" -o -name "*.ml" | head -20 > third_party/llms.txt 54 + echo "" >> third_party/llms.txt 55 + echo "=== Key Modules ===" >> third_party/llms.txt 56 + find third_party/<package-name>.<version> -name "*.mli" | xargs -I {} basename {} .mli >> third_party/llms.txt 57 + ``` 58 + 59 + A better approach is to use the package's documentation: 60 + 61 + ```bash 62 + # If the package has good documentation, reference that 63 + echo "Package: <package-name>" > third_party/llms.txt 64 + echo "Location: third_party/<package-name>.<version>" >> third_party/llms.txt 65 + echo "Documentation: See README.md and .mli files" >> third_party/llms.txt 66 + echo "" >> third_party/llms.txt 67 + echo "=== Main Modules ===" >> third_party/llms.txt 68 + find third_party/<package-name>.<version> -name "*.mli" -exec basename {} \; | sort >> third_party/llms.txt 69 + ``` 70 + 71 + ## Example Workflow 72 + 73 + ```bash 74 + # Search for eio package 75 + opam search eio 76 + 77 + # Create third_party directory 78 + mkdir -p third_party 79 + cd third_party 80 + 81 + # Fetch eio sources 82 + opam source eio 83 + 84 + # Return to project root 85 + cd .. 86 + 87 + # Add to root dune file 88 + echo "(data_only_dirs third_party)" >> dune 89 + 90 + # Add to .gitignore 91 + echo "third_party/" >> .gitignore 92 + 93 + # Generate llms.txt summary 94 + cat > third_party/llms.txt << EOF 95 + Package: eio 96 + Location: third_party/eio.* 97 + Purpose: Effects-based I/O library for OCaml 98 + 99 + Key modules available in .mli files for reference. 100 + EOF 101 + ``` 102 + 103 + ## When to Fetch Sources 104 + 105 + Fetch third-party sources when you need to: 106 + - Understand how to use complex APIs 107 + - Reference implementation patterns 108 + - Study mock/test infrastructure (e.g., Eio.Mock) 109 + - Debug interactions with dependencies 110 + - Learn from well-written code 111 + 112 + ## Notes 113 + 114 + - Sources are fetched based on your current opam switch 115 + - Sources are not committed to git (listed in .gitignore) 116 + - Each developer can fetch sources as needed 117 + - Dune ignores these directories completely (data_only_dirs) 118 + - Update llms.txt when adding new third-party sources for better discoverability
+224
TESTS.md
··· 1 + # Testing Strategies for OCaml Libraries 2 + 3 + ## Overview 4 + 5 + Testing strategies vary based on your library's dependencies and I/O requirements. This guide covers different approaches with special attention to Eio-based libraries. 6 + 7 + ## General Testing Setup 8 + 9 + ### Basic Test Structure 10 + 11 + Tests typically use Alcotest: 12 + 13 + ```ocaml 14 + let test_basic () = 15 + Alcotest.(check int) "same ints" 42 (21 + 21) 16 + 17 + let suite = [ 18 + "basic", `Quick, test_basic; 19 + ] 20 + 21 + let () = Alcotest.run "MyLibrary" [ 22 + "suite1", suite; 23 + ] 24 + ``` 25 + 26 + ### Test Dependencies 27 + 28 + Add to your `dune-project` package stanza: 29 + 30 + ```lisp 31 + (depends 32 + ; ... other deps ... 33 + (alcotest (and :with-test (>= 1.7.0))) 34 + (eio_main :with-test) ; if using Eio 35 + ) 36 + ``` 37 + 38 + ## Testing Eio-Based Libraries 39 + 40 + ### Using Eio Mock Infrastructure 41 + 42 + If your library uses Eio, **prefer using Eio's mock infrastructure** for testing rather than running real I/O operations. This provides: 43 + - Deterministic tests 44 + - No actual filesystem/network operations 45 + - Better error injection and edge case testing 46 + - Faster test execution 47 + 48 + ### Step 1: Fetch Eio Sources 49 + 50 + Before writing Eio tests, fetch the Eio sources to understand the mock APIs: 51 + 52 + ```bash 53 + mkdir -p third_party 54 + cd third_party 55 + opam source eio 56 + cd .. 57 + 58 + # Add to root dune file 59 + echo "(data_only_dirs third_party)" >> dune 60 + 61 + # Add to .gitignore 62 + echo "third_party/" >> .gitignore 63 + ``` 64 + 65 + ### Step 2: Study Eio Mock APIs 66 + 67 + Key files to review in `third_party/eio.*/`: 68 + - `lib_eio/mock/` - Mock implementations 69 + - `tests/` - Example test patterns 70 + - Look for `Eio.Mock.*` modules 71 + 72 + Common mock modules: 73 + - `Eio_mock.Backend` - Mock backend for testing 74 + - `Eio_mock.Clock` - Deterministic clock 75 + - `Eio_mock.Flow` - Mock flows/streams 76 + - Mock filesystem, network, etc. 77 + 78 + ### Step 3: Write Tests Using Mocks 79 + 80 + Example test structure for an Eio-based library: 81 + 82 + ```ocaml 83 + (* test/test_mylib.ml *) 84 + 85 + let test_with_mock_fs () = 86 + Eio_mock.Backend.run @@ fun () -> 87 + let fs = Eio_mock.Flow.make "mock-fs" in 88 + (* Your test using the mock filesystem *) 89 + Alcotest.(check bool) "operation succeeded" true true 90 + 91 + let test_with_mock_clock () = 92 + Eio_mock.Backend.run @@ fun () -> 93 + let clock = Eio_mock.Clock.make () in 94 + (* Test time-dependent operations *) 95 + Eio_mock.Clock.advance clock 1.0; 96 + (* Check results after time advance *) 97 + Alcotest.(check bool) "timed out correctly" true true 98 + 99 + let suite = [ 100 + "mock filesystem", `Quick, test_with_mock_fs; 101 + "mock clock", `Quick, test_with_mock_clock; 102 + ] 103 + 104 + let () = Alcotest.run "MyLibrary" [ 105 + "eio-mocks", suite; 106 + ] 107 + ``` 108 + 109 + ### Step 4: Integration Tests with eio_main 110 + 111 + For integration tests that need real I/O (fewer of these): 112 + 113 + ```ocaml 114 + let test_real_io () = 115 + Eio_main.run @@ fun env -> 116 + (* Use real env#fs, env#clock, etc. *) 117 + (* Clean up any test files/state after *) 118 + () 119 + ``` 120 + 121 + ## Testing Strategies by Library Type 122 + 123 + ### Pure Libraries (No I/O) 124 + 125 + - Use simple Alcotest cases 126 + - Focus on property-based testing if appropriate 127 + - No special infrastructure needed 128 + 129 + ### Libraries with Filesystem I/O 130 + 131 + **If using Eio:** 132 + - Use `Eio_mock` filesystem 133 + - Study `third_party/eio.*/` for patterns 134 + 135 + **If not using Eio:** 136 + - Create temporary directories in tests 137 + - Clean up in test teardown 138 + - Use `Filename.temp_file` and similar 139 + 140 + ### Libraries with Network I/O 141 + 142 + **If using Eio:** 143 + - Use `Eio_mock` network mocks 144 + - Test connection failures, timeouts 145 + - No actual network calls in unit tests 146 + 147 + **If not using Eio:** 148 + - Mock at the protocol level 149 + - Use loopback interfaces if needed 150 + - Prefer unit tests over integration tests 151 + 152 + ### Libraries with Time/Concurrency 153 + 154 + **If using Eio:** 155 + - Use `Eio_mock.Clock` for deterministic time 156 + - Advance time explicitly in tests 157 + - Test races and timeouts reliably 158 + 159 + **If using Lwt/Async:** 160 + - Use testing utilities from those libraries 161 + - Be careful with timing-dependent tests 162 + 163 + ## Test Organization 164 + 165 + ``` 166 + project/ 167 + ├── lib/ 168 + │ └── mylib.ml 169 + ├── test/ 170 + │ ├── dune # Test executable configuration 171 + │ ├── test_mylib.ml # Unit tests 172 + │ └── test_integration.ml # Integration tests (if needed) 173 + └── third_party/ # Fetched sources for reference 174 + ├── eio.*/ # Eio source (if applicable) 175 + └── llms.txt # Summary of available sources 176 + ``` 177 + 178 + ### Test dune file 179 + 180 + ```lisp 181 + (test 182 + (name test_mylib) 183 + (libraries mylib alcotest eio_main)) 184 + ``` 185 + 186 + ## Best Practices 187 + 188 + 1. **Prefer mocks over real I/O** - Tests should be fast and deterministic 189 + 2. **Fetch dependency sources** - Understand mock APIs by reading source 190 + 3. **Study existing tests** - Look at `third_party/eio.*/tests/` for patterns 191 + 4. **Keep integration tests minimal** - Most tests should use mocks 192 + 5. **Clean up resources** - Even in tests, clean up temp files/state 193 + 6. **Test edge cases** - Use mocks to inject errors and edge conditions 194 + 195 + ## Running Tests 196 + 197 + ```bash 198 + # Run all tests 199 + dune runtest 200 + 201 + # Run tests verbosely 202 + dune runtest --verbose 203 + 204 + # Run specific test 205 + dune exec -- test/test_mylib.exe 206 + 207 + # Run with coverage (if configured) 208 + dune runtest --instrument-with bisect_ppx 209 + ``` 210 + 211 + ## Continuous Integration 212 + 213 + The default `.tangled/workflows/build.yml` includes test steps: 214 + 215 + ```yaml 216 + - name: switch-test 217 + command: | 218 + opam install . --confirm-level=unsafe-yes --deps-only --with-test 219 + - name: test 220 + command: | 221 + opam exec -- dune runtest --verbose 222 + ``` 223 + 224 + If you need additional test setup (e.g., fetching sources for test development), document it in the README but **do not** add it to CI (sources should not be required for running tests, only for understanding how to write them).
+4
dune
··· 1 + ; Root dune file 2 + 3 + ; Ignore third_party directory (for fetched dependency sources) 4 + (data_only_dirs third_party)
+32
dune-project
··· 1 + (lang dune 3.20) 2 + 3 + (name my-library) ; Update with your library name 4 + 5 + (generate_opam_files true) 6 + 7 + (license ISC) 8 + (authors "Anil Madhavapeddy") 9 + (homepage "https://tangled.org/@anil.recoil.org/my-library") ; Update with your project URL 10 + (maintainers "Anil Madhavapeddy <anil@recoil.org>") 11 + (bug_reports "https://tangled.org/@anil.recoil.org/my-library/issues") ; Update with your project URL 12 + (maintenance_intent "(latest)") 13 + 14 + ; NOTE: Do NOT add a (source ...) field for Tangled projects 15 + ; Tangled uses the homepage/bug_reports URLs to determine the source repository 16 + 17 + (package 18 + (name my-library) ; Update with your library name 19 + (synopsis "Brief one-line description of your library") ; Update with your synopsis 20 + (description 21 + "Longer description of your library. \ 22 + Explain what it does, its main features, \ 23 + and how it should be used.") ; Update with your description 24 + (depends 25 + (ocaml (>= 5.1.0)) 26 + ; Add your runtime dependencies here 27 + ; Example: (lwt (>= 5.0)) 28 + ; Example: (cmdliner (>= 1.2.0)) 29 + (odoc :with-doc) 30 + ; Add your test dependencies here 31 + ; Example: (alcotest (and :with-test (>= 1.7.0))) 32 + ))