import { describe, expect, test } from 'bun:test'
import { hasFileExtension, parseSingleByteRange } from './file-serving'
describe('hasFileExtension', () => {
describe('paths with extensions', () => {
test('simple file extension', () => {
expect(hasFileExtension('style.css')).toBe(true)
})
test('html extension', () => {
expect(hasFileExtension('index.html')).toBe(true)
})
test('nested path with extension', () => {
expect(hasFileExtension('assets/js/app.js')).toBe(true)
})
test('double extension', () => {
expect(hasFileExtension('archive.tar.gz')).toBe(true)
})
test('dotfile with extension', () => {
expect(hasFileExtension('.htaccess')).toBe(true)
})
test('minified file', () => {
expect(hasFileExtension('bundle.min.js')).toBe(true)
})
test('image file', () => {
expect(hasFileExtension('photo.png')).toBe(true)
})
test('sourcemap', () => {
expect(hasFileExtension('app.js.map')).toBe(true)
})
})
describe('paths without extensions (extensionless files)', () => {
test('simple name', () => {
expect(hasFileExtension('about')).toBe(false)
})
test('binary-style name with dashes', () => {
expect(hasFileExtension('wisp-cli-x86_64-linux')).toBe(false)
})
test('binary-style name with underscores', () => {
expect(hasFileExtension('my_binary_v2')).toBe(false)
})
test('empty string', () => {
expect(hasFileExtension('')).toBe(false)
})
test('single word', () => {
expect(hasFileExtension('README')).toBe(false)
})
test('path with trailing slash', () => {
expect(hasFileExtension('somedir/')).toBe(false)
})
})
describe('directory-with-dot edge cases', () => {
test('dot in directory name, extensionless file', () => {
expect(hasFileExtension('my.folder/file')).toBe(false)
})
test('dot in directory name, file with extension', () => {
expect(hasFileExtension('my.folder/index.html')).toBe(true)
})
test('multiple dotted directories, extensionless file', () => {
expect(hasFileExtension('v1.0/api.v2/handler')).toBe(false)
})
test('multiple dotted directories, file with extension', () => {
expect(hasFileExtension('v1.0/api.v2/handler.js')).toBe(true)
})
})
describe('trailing-dot edge case', () => {
test('trailing dot is not a file extension', () => {
// "file." has a dot but no alphanumeric chars after it
expect(hasFileExtension('file.')).toBe(false)
})
})
})
describe('parseSingleByteRange', () => {
test('parses bounded, open-ended, and suffix ranges', () => {
expect(parseSingleByteRange('bytes=2-5', 10)).toEqual({ start: 2, end: 5 })
expect(parseSingleByteRange('bytes=7-', 10)).toEqual({ start: 7, end: 9 })
expect(parseSingleByteRange('bytes=-3', 10)).toEqual({ start: 7, end: 9 })
})
test('caps an end offset and rejects unsatisfiable ranges', () => {
expect(parseSingleByteRange('bytes=8-99', 10)).toEqual({ start: 8, end: 9 })
expect(parseSingleByteRange('bytes=10-20', 10)).toBe('unsatisfiable')
expect(parseSingleByteRange('bytes=5-2', 10)).toBe('unsatisfiable')
})
test('ignores malformed or multipart syntax', () => {
expect(parseSingleByteRange('items=0-1', 10)).toBeNull()
expect(parseSingleByteRange('bytes=0-1,4-5', 10)).toBeNull()
})
})