Skip to content
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
17 changes: 17 additions & 0 deletions textrun-workspace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ Now file _greeting/hello.txt_ has content `hello sun and moonlight`.

</a>

## compare-files

The <code type="action/name-full">workspace/compare-files</code> action compares
the content of the given files.

Assume the workspace contains file <a type="workspace/new-file"> _one.txt_, with
content `hello`</a>, and file <a type="workspace/new-file"> _two.txt_, also with
content `hello`</a>. Then this documentation passes:

<a type="extension/runnable-region">

```html
<a type="workspace/compare-files" have="one.txt" want="two.txt"></a>.
```

</a>

## copy-file

The <code type="action/name-full">workspace/copy-file</code> action copies the
Expand Down
147 changes: 147 additions & 0 deletions textrun-workspace/features/compare-files.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
Feature: compare files

Scenario: compare matching files
Given the workspace contains a file "have.txt" with content:
"""
same file content
"""
And the workspace contains a file "want.txt" with content:
"""
same file content
"""
And the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="have.txt" want="want.txt"></a>.
"""
When calling Text-Runner
Then it runs these actions:
| FILENAME | LINE | ACTION | ACTIVITY |
| compare.md | 1 | workspace/compare-files | compare files have.txt and want.txt |

Scenario: have not provided
Given the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" want="want.txt"></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | Workspace compare files |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | Missing attribute: have |
| GUIDANCE | Please provide the file to verify via the "have" attribute |

Scenario: have is empty
Given the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="" want="want.txt"></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | Workspace compare files |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | Missing attribute: have |
| GUIDANCE | Please provide the file to verify via the "have" attribute |

Scenario: want not provided
Given the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="have.txt"></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | Workspace compare files |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | Missing attribute: want |
| GUIDANCE | Please provide the golden file via the "want" attribute |

Scenario: want is empty
Given the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="have.txt" want=""></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | Workspace compare files |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | Missing attribute: want |
| GUIDANCE | Please provide the golden file via the "want" attribute |

Scenario: have doesn't exist
And the workspace contains a file "want.txt" with content:
"""
same file content
"""
And the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="have.txt" want="want.txt"></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | compare files have.txt and want.txt |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | file not found: have.txt |
| GUIDANCE | the workspace has these files: want.txt |

Scenario: want doesn't exist
And the workspace contains a file "have.txt" with content:
"""
same file content
"""
And the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="have.txt" want="want.txt"></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | compare files have.txt and want.txt |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | file not found: want.txt |
| GUIDANCE | the workspace has these files: have.txt |

Scenario: files have different content
Given the workspace contains a file "have.txt" with content:
"""
have file content
"""
And the workspace contains a file "want.txt" with content:
"""
want file content
"""
And the source code contains a file "compare.md" with content:
"""
<a type="workspace/compare-files" have="have.txt" want="want.txt"></a>.
"""
When calling Text-Runner
Then it runs this action:
| FILENAME | compare.md |
| LINE | 1 |
| ACTION | workspace/compare-files |
| ACTIVITY | compare files have.txt and want.txt |
| STATUS | failed |
| ERROR TYPE | UserError |
| ERROR MESSAGE | mismatching content |
| GUIDANCE | mismatching lines:\n\nwant file contenthave file content |
53 changes: 53 additions & 0 deletions textrun-workspace/src/actions/compare-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as assertNoDiff from "assert-no-diff"
import { promises as fs } from "fs"
import { styleText } from "node:util"
import * as textRunner from "text-runner-engine"

export async function compareFiles(action: textRunner.actions.Args): Promise<void> {
const have = action.region[0].attributes["have"]
if (!have) {
throw new textRunner.UserError(
"Missing attribute: have",
'Please provide the file to verify via the "have" attribute'
)
}
const want = action.region[0].attributes["want"]
if (!want) {
throw new textRunner.UserError("Missing attribute: want", 'Please provide the golden file via the "want" attribute')
}

action.name(`compare files ${styleText("cyan", have)} and ${styleText("cyan", want)}`)

const haveContent = await readFile(have, action.configuration.workspace)
const wantContent = await readFile(want, action.configuration.workspace)

try {
assertNoDiff.trimmedLines(haveContent.trim(), wantContent.trim())
} catch (err) {
action.log(haveContent)
throw new textRunner.UserError(
`mismatching content`,
textRunner.errorMessage(err)
)
}
}

async function readFile(fileName: string, workspace: textRunner.files.AbsoluteDirPath): Promise<string> {
const filePath = workspace.joinStr(fileName)
try {
return await fs.readFile(filePath, "utf-8")
} catch (e) {
if (!textRunner.isFsError(e)) {
throw e
}
if (e.code === "ENOENT") {
const files = await fs.readdir(workspace.platformified())
throw new textRunner.UserError(
`file not found: ${fileName}`,
`the workspace has these files: ${files.join(", ")}`
)
} else {
throw e
}
}
}
2 changes: 2 additions & 0 deletions textrun-workspace/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as textRunner from "text-runner"

import { appendFile } from "./actions/append-file.js"
import { compareFiles } from "./actions/compare-files.js"
import { copyFile } from "./actions/copy-file.js"
import { emptyFile } from "./actions/empty-file.js"
import { existingDirectory } from "./actions/existing-directory.js"
Expand All @@ -12,6 +13,7 @@ import { workingDir } from "./actions/working-dir.js"

export const textrunActions: textRunner.exports.TextrunActions = {
appendFile,
compareFiles,
copyFile,
emptyFile,
existingDirectory,
Expand Down