Skip to content

Turn eqeq in doc comments to asserts for testing #7531

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

Merged
merged 2 commits into from
Jun 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion runtime/Belt_HashMap.resi
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ let s1 = Belt.HashMap.copy(s0)

Belt.HashMap.set(s0, 2, "3")

assertEqual(Belt.HashMap.get(s0, 2) == Belt.HashMap.get(s1, 2), false)
assertEqual(Belt.HashMap.get(s0, 2) != Belt.HashMap.get(s1, 2), true)
```
*/
let copy: t<'key, 'value, 'id> => t<'key, 'value, 'id>
Expand Down
14 changes: 7 additions & 7 deletions runtime/Stdlib_Console.resi
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on MDN.

```rescript
Console.assert_(false, "Hello World!")
Console.assert_(42 == 42, "The answer")
Console.assert_(42 === 42, "The answer")
```
*/
@val
Expand All @@ -27,7 +27,7 @@ external assert_: (bool, 'a) => unit = "console.assert"

```rescript
Console.assert2(false, "Hello", "World")
Console.assert2(42 == 42, [1, 2, 3], '4')
Console.assert2(42 === 42, [1, 2, 3], '4')
```
*/
@val
Expand All @@ -40,7 +40,7 @@ external assert2: (bool, 'a, 'b) => unit = "console.assert"

```rescript
Console.assert3(false, "Hello", "World", "ReScript")
Console.assert3(42 == 42, "One", 2, #3)
Console.assert3(42 === 42, "One", 2, #3)
```
*/
@val
Expand All @@ -54,7 +54,7 @@ external assert3: (bool, 'a, 'b, 'c) => unit = "console.assert"
```rescript
let value = 42
Console.assert4(false, "Hello", "World", "ReScript", "!!!")
Console.assert4(value == 42, [1, 2], (3, 4), [#5, #6], #"polyvar")
Console.assert4(value === 42, [1, 2], (3, 4), [#5, #6], #"polyvar")
```
*/
@val
Expand All @@ -68,7 +68,7 @@ external assert4: (bool, 'a, 'b, 'c, 'd) => unit = "console.assert"
```rescript
let value = 42
Console.assert5(false, "Hello", "World", "JS", '!', '!')
Console.assert5(value == 42, [1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"})
Console.assert5(value === 42, [1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"})
```
*/
@val
Expand All @@ -82,7 +82,7 @@ external assert5: (bool, 'a, 'b, 'c, 'd, 'e) => unit = "console.assert"
```rescript
let value = 42
Console.assert6(false, "Hello", "World", "JS", '!', '!', '?')
Console.assert6(value == 42, [1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42)
Console.assert6(value === 42, [1, 2], (3, 4), [#5, #6], #"polyvar", {"name": "ReScript"}, 42)
```
*/
@val
Expand All @@ -96,7 +96,7 @@ external assert6: (bool, 'a, 'b, 'c, 'd, 'e, 'f) => unit = "console.assert"
```rescript
let value = 42
Console.assertMany(false, ["Hello", "World"])
Console.assertMany(value == 42, [1, 2, 3])
Console.assertMany(value === 42, [1, 2, 3])
```
*/
@val
Expand Down
7 changes: 2 additions & 5 deletions runtime/Stdlib_String.resi
Original file line number Diff line number Diff line change
Expand Up @@ -891,11 +891,8 @@ See [`String.split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Ref
## Examples

```rescript
String.splitByRegExpAtMost("Hello World. How are you doing?", %re("/ /"), ~limit=3) == [
Some("Hello"),
Some("World."),
Some("How"),
]
String.splitByRegExpAtMost("Hello World. How are you doing?", / /, ~limit=3) ==
[Some("Hello"), Some("World."), Some("How")]
```
*/
@send
Expand Down
2 changes: 1 addition & 1 deletion scripts/format_check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ case "$(uname -s)" in
if ./cli/rescript.js format -check $files; then
printf "${successGreen}✅ ReScript code formatting ok.${reset}\n"
else
printf "${warningYellow}⚠️ ReScript code formatting issues found.${reset}\n"
printf "${warningYellow}⚠️ ReScript code formatting issues found. Run 'make format' to fix.${reset}\n"
exit 1
fi
;;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ Path s
"kind": 12,
"tags": [],
"detail": "(string, RegExp.t, ~limit: int) => array<option<string>>",
"documentation": {"kind": "markdown", "value": "\n`splitByRegExpAtMost(str, regexp, ~limit)` splits the given `str` at every\noccurrence of `regexp` and returns an array of the first `limit` resulting\nsubstrings. If `limit` is negative or greater than the number of substrings, the\narray will contain all the substrings.\nSee [`String.split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) on MDN.\n\n## Examples\n\n```rescript\nString.splitByRegExpAtMost(\"Hello World. How are you doing?\", %re(\"/ /\"), ~limit=3) == [\n Some(\"Hello\"),\n Some(\"World.\"),\n Some(\"How\"),\n]\n```\n"},
"documentation": {"kind": "markdown", "value": "\n`splitByRegExpAtMost(str, regexp, ~limit)` splits the given `str` at every\noccurrence of `regexp` and returns an array of the first `limit` resulting\nsubstrings. If `limit` is negative or greater than the number of substrings, the\narray will contain all the substrings.\nSee [`String.split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) on MDN.\n\n## Examples\n\n```rescript\nString.splitByRegExpAtMost(\"Hello World. How are you doing?\", / /, ~limit=3) ==\n [Some(\"Hello\"), Some(\"World.\"), Some(\"How\")]\n```\n"},
"sortText": "splitByRegExpAtMost",
"insertText": "->String.splitByRegExpAtMost",
"additionalTextEdits": [{
Expand Down
107 changes: 97 additions & 10 deletions tests/docstring_tests/DocTest.res
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,96 @@ let getCodeBlocks = example => {
}
}

// Transform lines that contain == patterns to use assertEqual
let transformEqualityAssertions = code => {
let lines = code->String.split("\n")
lines
->Array.mapWithIndex((line, idx) => {
let trimmedLine = line->String.trim

// Check if the line contains == and is not inside a comment
if (
trimmedLine->String.includes("==") &&
!(trimmedLine->String.startsWith("//")) &&
!(trimmedLine->String.startsWith("/*")) &&
// Not an expression line
!(trimmedLine->String.startsWith("if")) &&
!(trimmedLine->String.startsWith("|")) &&
!(trimmedLine->String.startsWith("let")) &&
!(trimmedLine->String.startsWith("~")) &&
!(trimmedLine->String.startsWith("module")) &&
!(trimmedLine->String.startsWith("->")) &&
!(trimmedLine->String.endsWith(","))
) {
// Split string at == (not ===) and transform to assertEqual
let parts = {
let rec searchFrom = (currentLine: string, startIndex: int): option<(string, string)> => {
if startIndex >= currentLine->String.length {
// Base case: reached end of string without finding a suitable "=="
None
} else {
let lineSuffix = currentLine->String.sliceToEnd(~start=startIndex)
let idxEqEqInSuffix = lineSuffix->String.indexOfOpt("==")
let idxEqEqEqInSuffix = lineSuffix->String.indexOfOpt("===")

switch (idxEqEqInSuffix, idxEqEqEqInSuffix) {
| (None, _) =>
// No "==" found in the rest of the string.
None
| (Some(iEqEq), None) =>
// Found "==" but no "===" in the suffix.
// This "==" must be standalone.
// Calculate its absolute index in the original `currentLine`.
let actualIdx = startIndex + iEqEq
let left = currentLine->String.slice(~start=0, ~end=actualIdx)
let right = currentLine->String.sliceToEnd(~start=actualIdx + 2)
Some((left, right))
| (Some(iEqEq), Some(iEqEqEq)) =>
// Found both "==" and "===" in the suffix.
if iEqEq < iEqEqEq {
// The "==" occurs before "===". This "==" is standalone.
// Example: "a == b === c". In suffix "a == b === c", iEqEq is for "a ==".
let actualIdx = startIndex + iEqEq
let left = currentLine->String.slice(~start=0, ~end=actualIdx)
let right = currentLine->String.sliceToEnd(~start=actualIdx + 2)
Some((left, right))
} else {
// iEqEq >= iEqEqEq
// This means the first "==" encountered (at iEqEq relative to suffix)
// is part of or comes after the first "===" encountered (at iEqEqEq relative to suffix).
// Example: "a === b". In suffix "a === b", iEqEqEq is for "a ===", iEqEq is also for "a ==".
// We must skip over the "===" found at iEqEqEq and search again.
// The next search should start after this "===".
// The "===" starts at (startIndex + iEqEqEq) in the original line. It has length 3.
searchFrom(currentLine, startIndex + iEqEqEq + 3)
}
}
}
}
searchFrom(line, 0)
}
let parts = switch parts {
| Some((left, right)) if right->String.trim->String.length === 0 =>
Some((
left,
lines
->Array.get(idx + 1)
->Option.getExn(~message="Expected to have an expected expression on the next line"),
))
| _ => parts
}
switch parts {
| Some((left, right)) if !(right->String.includes(")") || right->String.includes("//")) =>
`(${left->String.trim})->assertEqual(${right->String.trim})`
| _ => line
}
} else {
line
}
})
->Array.join("\n")
}

let rec loop = (lines: list<string>, acc: list<string>) => {
switch lines {
| list{hd, ...rest} =>
Expand All @@ -120,16 +210,13 @@ let getCodeBlocks = example => {
->String.startsWith("```res") {
| true =>
let code = loopEndCodeBlock(rest, list{})
loop(
rest,
list{
code
->List.reverse
->List.toArray
->Array.join("\n"),
...acc,
},
)
let codeString =
code
->List.reverse
->List.toArray
->Array.join("\n")
->transformEqualityAssertions
loop(rest, list{codeString, ...acc})
| false => loop(rest, acc)
}
| list{} => acc
Expand Down
61 changes: 60 additions & 1 deletion tests/docstring_tests/DocTest.res.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.