Skip to content
BeispielWerk
Deutsch

Test data edge cases: ready-made fixtures for CSV, Unicode, JSON, dates and APIs

Fixtures for the cases that break importers, parsers and validators. Each file says what it tests and what a correct program does with it. Deliberately broken files are labelled and name the exact rule they violate, so they never hide inside normal sample data.

Manifest

  • Manifest: every fixture with what it tests and what to expectFictional

    [
      {
        "file": "quoted-commas.csv", …

    One JSON array describing all fixtures: file, category, status, what it tests, the expected behaviour and, for invalid files, the violated rule. Use it to drive a test loop.

CSV imports (11 files, 3 deliberately invalid)

Files that break naive CSV code: delimiters inside quotes, line breaks inside fields, byte order marks, ragged rows and spreadsheet formulas. Parse them with your importer and compare the result with the expectation.

  • CSV with commas and quotes inside quoted fieldsFictional

    id,name,note
    1,"Muster, Max","Said ""hello"", then left"
    2,"Beispiel, Eva","Plain note" …

    Tests: A delimiter and escaped quotes inside a quoted field (RFC 4180). Expected: 3 data rows, 3 columns each; the name column of row 1 is: Muster, Max.

  • CSV with line breaks inside quoted fieldsFictional

    id,note
    1,"line one
    line two …

    Tests: A record that spans several physical lines. Expected: 2 data rows; the note of row 1 has 3 lines. Counting physical lines (6) gives the wrong row count.

  • CSV with semicolons, decimal commas and German datesFictional

    id;price;date
    1;12,50;24.10.2026
    2;1.299,00;01.11.2026 …

    Tests: German spreadsheet export: delimiter ; and decimal comma, date as DD.MM.YYYY. Expected: Delimiter detected as ;. Price 12,50 is 12.50, not two fields; 24.10.2026 is 24 October 2026.

  • CSV that starts with a UTF-8 byte order markFictional

    name,city
    Anna,Musterstadt
    Jonas,Beispieldorf

    Tests: A BOM (U+FEFF) before the first header. Expected: The first column is named name, not name. Header lookup by name must succeed.

  • CSV with Windows line endings (CRLF)Fictional

    a,b,c
    1,2,3
    4,5,6 …

    Tests: CRLF instead of LF; no stray CR at the end of the last column. Expected: Last column values are 1, 2, 3 without a trailing carriage return.

  • Risky: CSV with blank lines inside and at the endFictional

    id,name
    1,Anna
     …

    Tests: Importers disagree about empty lines. Expected: Either skip blank lines or report them with their line number; never produce rows of empty strings silently.

  • CSV with leading zeros that must stay textFictional

    zip,city
    01067,Musterstadt
    00123,Beispieldorf …

    Tests: Postal codes and codes that lose their zeros when read as numbers. Expected: The zip column keeps 01067 and 00123 as text; reading them as numbers is a bug.

  • Risky: CSV with spreadsheet formula characters in cellsFictional

    id,value
    1,=1+1
    2,+1 …

    Tests: Cells starting with =, +, - or @ are executed as formulas when opened in a spreadsheet. Expected: Exports prefix such cells (for example with an apostrophe) or quote them; imports treat them as text. The formulas here are harmless.

  • Invalid CSV: rows with too few and too many fieldsDeliberately invalid

    id,name,city
    1,Anna,Musterstadt
    2,Jonas …

    Tests: Row width differs from the header. Violates: RFC 4180: every record has the same number of fields as the header. Expected: Reject the file or report lines 3 and 4 with the expected and actual field count.

  • Invalid CSV: duplicate column namesDeliberately invalid

    id,name,name
    1,Anna,Mueller
    2,Jonas,Schmidt

    Tests: Two columns called name. Violates: Column names must be unique to address values by name. Expected: Reject the file, or rename the second column explicitly (name_2) and tell the user. Never let one silently overwrite the other.

  • Invalid CSV: quote that is never closedDeliberately invalid

    id,note
    1,"never closed
    2,next row …

    Tests: An opening quote without a closing one swallows the rest of the file. Violates: RFC 4180: a quoted field must end with a closing quote before the delimiter or line end. Expected: Report an error at line 2 (unterminated quoted field) instead of returning one giant cell.

Unicode text (6 files, 1 deliberately invalid)

The same visible text can be stored in different ways. These fixtures list code points, UTF-16 units and UTF-8 bytes (computed, not typed) so you can test length limits, comparison, sorting, casing and truncation.

  • Unicode: same text, different normalization (NFC and NFD)Fictional

    [
      {
        "label": "e acute, precomposed (NFC)", …

    Tests: Visually identical strings that compare unequal. Expected: Normalize (NFC) before comparing, searching or enforcing uniqueness; é and e + U+0301 must match.

  • Unicode: one visible character, many code pointsFictional

    [
      {
        "label": "family emoji (ZWJ sequence)", …

    Tests: Length limits and truncation that count code units or code points instead of characters. Expected: A limit of 1 character admits each of these; cutting them in the middle produces broken glyphs.

  • Unicode: casing that is not one-to-oneFictional

    [
      {
        "label": "German sharp s, uppercase", …

    Tests: Upper and lower casing that changes the length or depends on the locale. Expected: Do case-insensitive comparison with case folding, not toLowerCase on both sides, and pass the right locale for Turkish.

  • Risky: Unicode: invisible characters inside namesFictional

    [
      {
        "label": "plain", …

    Tests: Values that look equal but differ, so uniqueness checks, trimming and lookups fail. Expected: Strip or reject zero width and format characters in identifiers; trim() alone does not remove U+200B or U+2060.

  • Unicode: right-to-left text mixed with numbers and LatinFictional

    [
      {
        "label": "Arabic greeting", …

    Tests: Display order differs from storage order. Expected: Store and compare in logical order; use bidi isolation (dir="auto" or isolate marks) when inserting such text into a sentence.

  • Invalid Unicode: unpaired surrogates in JSON escapesDeliberately invalid

    [
      "�",
      "�", …

    Tests: JSON syntax allows the escapes, but a lone surrogate is not a Unicode scalar value. Violates: Unicode: surrogate code points (U+D800 to U+DFFF) are not scalar values and cannot be encoded in UTF-8 (RFC 3629). Expected: Reject the string, or replace each lone surrogate with U+FFFD and say so. The third entry is a valid surrogate pair (an emoji).

JSON documents (5 files, 1 deliberately invalid)

Null versus missing, numbers that do not survive a double, duplicate keys, deep nesting and a trailing comma. Some are valid JSON that still trips programs; one is not JSON at all.

  • JSON: null, missing and empty string are three different thingsFictional

    [
      {
        "id": 1, …

    Tests: Optional fields that are null, absent or empty. Expected: Treat the three records differently where the difference matters (clear a value, leave it unchanged, set it to empty).

  • Risky: JSON: numbers that do not survive a doubleFictional

    {
      "id_as_number": 9007199254740993,
      "id_as_string": "9007199254740993", …

    Tests: Integers above 2^53 and decimal fractions parsed as IEEE 754 doubles. Expected: Parsing 9007199254740993 as a number gives 9007199254740992. Send identifiers above 2^53 as strings and money as integer cents.

  • Risky: JSON: duplicate keys in one objectFictional

    {
      "status": "active",
      "amount": 1, …

    Tests: Syntactically valid JSON whose meaning is undefined. Expected: Most parsers keep the last value (here 2). A strict parser or schema validator should reject the document or report the duplicate.

  • JSON: 100 levels of nestingFictional

    {"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"child":{"chil …

    Tests: Recursion limits in parsers and serializers. Expected: Parse successfully, or fail with a clear depth-limit error; never crash the process. The deepest value is {"leaf": true}.

  • Invalid JSON: trailing commaDeliberately invalid

    {
      "a": 1,
      "b": [1, 2, 3,], …

    Tests: A comma before a closing bracket, common in hand-edited files. Violates: RFC 8259: a trailing comma after the last array element or member is not allowed. Expected: Reject with an error that points at line 4 (strict parser). Only JSON5 or JSONC parsers accept it.

Dates, time zones and DST (3 files)

Wall-clock times that do not exist or happen twice, calendar dates that look valid but are not, ISO week numbers around New Year and Unix timestamp limits. All values are computed with the platform time zone database.

  • Dates: daylight saving transitions in Europe/Berlin and America/New_York (2026)Fictional

    {
      "note": "All instants and offsets below are computed from the platform time zone database.",
      "europe_berlin": { …

    Tests: Local times that do not exist or occur twice, and days that are not 24 hours long. Expected: Store instants in UTC with the zone name; reject or shift the nonexistent time explicitly; decide which of the two occurrences an ambiguous time means.

  • Dates: leap days, impossible dates and month arithmeticFictional

    {
      "dates": [
        { …

    Tests: Dates that look valid but are not, and month arithmetic that overflows. Expected: Validate with a real calendar, not a regex. Decide and document how adding a month to the 31st behaves (clamp or overflow).

  • Dates: ISO week numbers around New Year and Unix timestamp limitsFictional

    {
      "iso_weeks": [
        { …

    Tests: The ISO year differs from the calendar year; Unix time overflows 32 bits in 2038 and mixes seconds with milliseconds. Expected: Use the ISO week-year (not the calendar year) with a week number; use 64-bit timestamps and name the unit.

Numbers and money (3 files)

Floating point traps, rounding rules that disagree with each other, and integer limits. Money should be stored in integer cents; these files show why.

  • Numbers: VAT rounding rules that disagreeFictional

    {
      "rule_note": "vat = net_cents * rate_percent / 100, rounded to whole cents",
      "cases": [ …

    Tests: Half-cent cases where rounding half away from zero, half to even and Math.round differ. Expected: Pick one rule per jurisdiction, apply it per line item, and write it down. Compare your result with the matching column.

  • Risky: Numbers: integer limits and values JSON cannot carryFictional

    [
      {
        "label": "largest safe integer (2^53 - 1)", …

    Tests: Safe integer range, 32-bit and 64-bit limits, and special values that JSON numbers cannot express. Expected: Keep identifiers above 2^53 as strings; never parse Infinity or NaN from JSON numbers; reject values outside the target column type.

  • Risky: Numbers: long identifiers in a CSV that a spreadsheet will roundFictional

    id,reference,amount
    9007199254740993,00123,10.50
    1234567890123456,00007,0.05

    Tests: A 16 digit identifier and a leading zero in a CSV opened in a spreadsheet. Expected: Import the id column as text. A spreadsheet shows 9.00719E+15 and drops the zero otherwise.

API responses (4 files)

Empty lists, the last page of a paginated result, RFC 9457 problem details, validation errors and query parameters that a robust API must reject or clamp.

  • API: empty list responseFictional

    {
      "items": [],
      "page": 1, …

    Tests: A successful request that matches nothing. Expected: Render an empty state, not an error. The status is 200 and items is an empty array, never null.

  • API: partially filled last pageFictional

    {
      "items": [
        { …

    Tests: The last page has fewer items than per_page; page 4 does not exist. Expected: Show 3 items on page 3 and disable "next". Requesting page 4 returns an empty list or 404, as documented.

  • API: RFC 9457 problem details errorFictional

    {
      "type": "https://example.com/problems/validation-error",
      "title": "Your request is not valid", …

    Tests: A machine-readable error body. Expected: Read type, title, status and detail; show detail to developers, not necessarily to end users; handle the extra errors array.

  • API: query parameters a robust API must reject or clampFictional

    [
      {
        "request": "GET https://example.com/api/orders?limit=0", …

    Tests: Out-of-range and malformed pagination, sorting and filter parameters. Expected: Return 400 with a problem details body or clamp to documented limits; never return a 500 or run the sort expression.

Broken relations (sample shop) (9 files, 8 deliberately invalid)

One valid order from the sample shop, then eight copies that each break exactly one rule: a missing reference, a wrong total, a duplicate key, an impossible date. A validator must report the named rule and no other.

  • Sample shop: one valid order with all related rows (baseline)Fictional

    {
      "customers": [
        { …

    Tests: The baseline: a delivered order with its customer, addresses, products, items, payment and shipment. Expected: Your validator reports no violation. Compare each broken variant against this file.

  • Invalid sample shop order: order item points at a product that does not existDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: order item points at a product that does not exist. Violates: Foreign key order_items.product_id must reference products.id. Expected: Report order_items[0].product_id = prd_999 as an orphan reference.

  • Invalid sample shop order: order total is one cent offDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: order total is one cent off. Violates: total_gross_cents must equal the sum of the lines plus shipping. Expected: Report the order total as 1 cent higher than its lines plus shipping.

  • Invalid sample shop order: payment amount differs from the order totalDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: payment amount differs from the order total. Violates: A payment amount must equal total_gross_cents of its order. Expected: Report a payment amount 100 cents lower than the order total.

  • Invalid sample shop order: shipment dated before the orderDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: shipment dated before the order. Violates: shipped_at must be later than ordered_at. Expected: Report the shipment as earlier than the order.

  • Invalid sample shop order: two customers share one e-mail addressDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: two customers share one e-mail address. Violates: customers.email is unique. Expected: Report the duplicate address of customer cus_dup.

  • Invalid sample shop order: order item with a negative quantityDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: order item with a negative quantity. Violates: quantity must be greater than 0 (a return is a separate document). Expected: Report order_items[0].quantity = -1. Amounts are recomputed for the new quantity, so no other rule is broken.

  • Invalid sample shop order: order item with a tax rate of 9 %Deliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: order item with a tax rate of 9 %. Violates: This shop only knows the tax rates 0 and 7. Expected: Report tax_rate = 9 as not allowed. Amounts are recomputed for 9 %, so no other rule is broken.

  • Invalid sample shop order: shipping address belongs to another customerDeliberately invalid

    {
      "customers": [
        { …

    Tests: The baseline order with exactly one defect: shipping address belongs to another customer. Violates: orders.shipping_address_id must reference an address of the order's customer. Expected: Report the shipping address adr_foreign as owned by cus_other.

How to use the fixtures in a test suite

Download the manifest, then loop over it. Each entry tells your test what to expect: valid files must be accepted, invalid files must be rejected with a useful message, risky files must be handled in a documented way.

import { readFileSync } from 'node:fs'
const manifest = JSON.parse(readFileSync('edge-cases-manifest.json', 'utf8'))
for (const f of manifest) {
  const text = readFileSync(f.file, 'utf8')
  const result = tryImport(text)           // your importer
  if (f.status === 'valid') expect(result.ok).toBe(true)
  if (f.status === 'invalid') expect(result.ok).toBe(false)   // and check the message names the rule
}

What is in each group

  • CSV imports (11 files, 3 deliberately invalid): Files that break naive CSV code: delimiters inside quotes, line breaks inside fields, byte order marks, ragged rows and spreadsheet formulas. Parse them with your importer and compare the result with the expectation.
  • Unicode text (6 files, 1 deliberately invalid): The same visible text can be stored in different ways. These fixtures list code points, UTF-16 units and UTF-8 bytes (computed, not typed) so you can test length limits, comparison, sorting, casing and truncation.
  • JSON documents (5 files, 1 deliberately invalid): Null versus missing, numbers that do not survive a double, duplicate keys, deep nesting and a trailing comma. Some are valid JSON that still trips programs; one is not JSON at all.
  • Dates, time zones and DST (3 files): Wall-clock times that do not exist or happen twice, calendar dates that look valid but are not, ISO week numbers around New Year and Unix timestamp limits. All values are computed with the platform time zone database.
  • Numbers and money (3 files): Floating point traps, rounding rules that disagree with each other, and integer limits. Money should be stored in integer cents; these files show why.
  • API responses (4 files): Empty lists, the last page of a paginated result, RFC 9457 problem details, validation errors and query parameters that a robust API must reject or clamp.
  • Broken relations (sample shop) (9 files, 8 deliberately invalid): One valid order from the sample shop, then eight copies that each break exactly one rule: a missing reference, a wrong total, a duplicate key, an impossible date. A validator must report the named rule and no other.

Principles

  • Every file states its expectation. “What it tests” says which behaviour is exercised; “Expected” says what a correct program does.
  • One defect per invalid file. The broken sample shop orders each violate exactly one rule, checked by a separate validator, so a failing test points at one cause.
  • Computed, not typed. Anything that can be calculated (code points, byte lengths, DST offsets, ISO weeks, rounded cents) is calculated when the files are built.
  • Always the same bytes. The fixtures contain no random values and no current date.

Related

The valid baseline order and its eight broken copies come from the sample shop database, whose own data never contains a defect. Format checks for banking data are on the IBAN validator page.

Frequently asked questions

What do “valid”, “risky” and “invalid” mean?
Valid files are correct input that still trips naive code (a quoted comma, a time that happens twice). Risky files are accepted by the format but have undefined or dangerous meaning (duplicate JSON keys, spreadsheet formulas). Invalid files break a named rule on purpose; the rule is written in the note.
Why are broken files kept apart?
So nobody loads them by accident into a database or a demo. Normal sample data, such as the sample shop, never contains a defect; the defective copies live here, one rule per file.
How were the facts verified?
Lengths, offsets, week numbers and rounding results are computed by code, and automated tests re-check them against independent sources: the platform time zone database, a strict CSV reader, known Unicode constants and a separate validator for the shop orders.
Are there files in other encodings, such as Latin-1?
Not yet. This page shows text, so only files that survive being displayed and copied as UTF-8 are offered. Byte-level fixtures (Latin-1, UTF-16, files without a final newline) need a binary download and are not included.
Is any of the data real?
No. E-mail addresses use the reserved example.* domains, there are no real phone numbers or accounts, and the shop orders come from the invented sample shop.
Can I use the files in my tests and projects?
Yes. You may copy, modify and use these files for any purpose, including commercial projects, without asking and without attribution. The license is CC0 1.0 Universal. The files are provided as they are, without any warranty. All data is invented and must not be used to represent real people, accounts or transactions.