Skip to content
Open
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
22 changes: 22 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Normalise the line endings of the files whose committed text is compared
# against generated output by
# `common/src/__tests__/freebuff-public-data-use-copy.test.ts`.
#
# The copy in those files is compared verbatim, and the renderers emit LF only.
# The repository stores all of them as LF already, so the CRLF never comes from
# the commit -- it appears in the working tree on Windows, where
# `core.autocrlf=true` rewrites LF as CRLF on checkout. The resulting diff shows
# zero changed lines and the assertion still fails, because every line differs by
# one invisible `\r`.
#
# Pinning these to LF makes the checkout agree with the repository on every
# platform, which is the durable fix; the comparison no longer depends on
# whoever's line-ending convention last touched the working tree.
#
# Scoped to just the asserted files on purpose: a repo-wide `* text=auto eol=lf`
# would renormalise everything and bury this change in unrelated diff noise.
README.md text eol=lf
freebuff/cli/release/README.md text eol=lf
web/src/content/advanced/privacy.mdx text eol=lf
web/src/content/help/faq.mdx text eol=lf
landing-lab/src/components/sections/Faq.tsx text eol=lf
70 changes: 60 additions & 10 deletions common/src/__tests__/freebuff-public-data-use-copy.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, test } from 'bun:test'
import { readFileSync } from 'node:fs'
import { existsSync, readFileSync } from 'node:fs'
import { resolve } from 'node:path'

import {
Expand All @@ -14,8 +14,36 @@ import {

const REPO_ROOT = resolve(import.meta.dir, '../../..')

/**
* Whether this tree carries `path`. The public repository is an export of the
* private source tree, and the export ships neither the web app (`web/`) nor
* `landing-lab/`; a test that reads one of those paths is asserting against
* files that were never here. Skipping by presence keeps the check running in
* the private tree, where those files do exist, and reactivates it here by
* itself if the export ever grows to include them.
*/
function isInThisTree(path: string): boolean {
return existsSync(resolve(REPO_ROOT, path))
}

/**
* Collapse CRLF (and any stray lone CR) to LF so a file's line endings cannot
* decide whether its copy matches.
*
* The generated block is compared as text, but the committed files carry CRLF
* and there is no `.gitattributes` pinning either style, so on a CRLF checkout
* every line of the block differed from the LF-only renderer's output by a
* single invisible `\r`. The failure diff showed zero changed lines and the
* assertion still failed. Normalizing makes the test assert the copy it is
* named for — the words — rather than whoever's line-ending convention last
* touched the file.
*/
function normalizeLineEndings(text: string): string {
return text.replace(/\r\n?/g, '\n')
}

function readRepoFile(path: string): string {
return readFileSync(resolve(REPO_ROOT, path), 'utf8')
return normalizeLineEndings(readFileSync(resolve(REPO_ROOT, path), 'utf8'))
}

function generatedBlock(
Expand Down Expand Up @@ -46,7 +74,7 @@ describe('public Freebuff data-use copy', () => {
)
})

test.each([
for (const [path, markers, copy] of [
[
'README.md',
FREEBUFF_DATA_USE_GENERATED_MARKDOWN_BLOCK,
Expand All @@ -67,13 +95,35 @@ describe('public Freebuff data-use copy', () => {
FREEBUFF_DATA_USE_GENERATED_MDX_BLOCK,
renderFreebuffDataUseFaqMdx(),
],
] as const)('%s matches canonical generated copy', (path, markers, copy) => {
expect(generatedBlock(readRepoFile(path), markers)).toBe(copy)
})
] as const) {
test.skipIf(!isInThisTree(path))(
`${path} matches canonical generated copy`,
() => {
expect(generatedBlock(readRepoFile(path), markers)).toBe(copy)
},
)
}

const LANDING_FAQ = 'landing-lab/src/components/sections/Faq.tsx'

test.skipIf(!isInThisTree(LANDING_FAQ))(
'landing-lab uses the canonical data-use FAQ',
() => {
expect(readRepoFile(LANDING_FAQ)).toContain(
` q: '${FREEBUFF_PUBLIC_DATA_USE_COPY.storageQuestion}',
a: '${FREEBUFF_PUBLIC_DATA_USE_COPY.storageAnswer}',`,
)
},
)

test('landing-lab uses the canonical data-use FAQ', () => {
expect(readRepoFile('landing-lab/src/components/sections/Faq.tsx'))
.toContain(` q: '${FREEBUFF_PUBLIC_DATA_USE_COPY.storageQuestion}',
a: '${FREEBUFF_PUBLIC_DATA_USE_COPY.storageAnswer}',`)
test('line endings do not decide whether the copy matches', () => {
// The regression guard for the reader above: a CRLF rendering of the block
// is the same copy, and has to compare equal to the LF-only renderer's
// output. Before the reader normalized, this was the README failure — a
// diff with zero changed lines and one extra `\r` per line.
const copy = renderFreebuffDataUseFaqMarkdown()
expect(copy).not.toContain('\r')
expect(normalizeLineEndings(copy.replace(/\n/g, '\r\n'))).toBe(copy)
expect(normalizeLineEndings(copy)).toBe(copy)
})
})
Loading