{
  "kind": "runtime",
  "capability_id": "apps.bar-graph",
  "tool_id": "bar-graph",
  "engine": "bar-graph-runtime",
  "version": "2.1.0",
  "runtime_version": "2.1.0",
  "calculation_version": "2.1.0",
  "generated_at": "2026-08-19T22:32:15.117Z",
  "test_count": 13,
  "passed": 13,
  "failed": 0,
  "tests_summary": {
    "golden": {
      "total": 8,
      "passed": 8
    },
    "boundary": {
      "total": 5,
      "passed": 5
    },
    "published_behavior": {
      "total": 2,
      "passed": null,
      "note": "PNG export (image/png, bar-graph.png) and on-canvas tick labels are published page cases — not a pixel-level canvas attestation."
    }
  },
  "engine_tested": true,
  "runtime_tested": true,
  "expert_reviewed": false,
  "internally_reviewed": false,
  "source_checked": true,
  "last_reviewed": "2026-08-20",
  "page": "https://www.calculatorx.com/apps/bar-graph",
  "browser_support": {
    "status": "designed_for",
    "note": "Designed for modern Chrome, Edge, Firefox, and Safari. No version-locked browser matrix is published yet."
  },
  "assumptions": [
    "Scale domain is [min(0, min(values)), max(0, max(values))].",
    "Positive bars grow away from the zero baseline toward domainMax; negative bars toward domainMin.",
    "If every value is 0, domain is [0, 1] and all bars have length 0."
  ],
  "limitations": [
    "One series per chart. Malformed lines are skipped.",
    "Axis labels longer than about 8–10 characters are truncated on the canvas.",
    "PNG export is a local canvas snapshot, not a server-rendered image."
  ],
  "sources": [
    {
      "title": "Vega-Lite — Bar Chart with Negative Values and a Zero-Baseline",
      "url": "https://vega.github.io/vega-lite/examples/bar_negative.html",
      "supports": "Negative bars cross a zero baseline in the opposite direction"
    },
    {
      "title": "Vega-Lite — Scale",
      "url": "https://vega.github.io/vega-lite/docs/scale.html",
      "supports": "Quantitative bar scale includes zero unless explicitly disabled"
    }
  ],
  "fingerprint": "sha256:e5984c3a1a3aafcc7bdbb4c52bc9af015f8a68bce71e656ff81d401279e4b533",
  "tests": [
    {
      "id": "tc01-normal-positive",
      "kind": "golden",
      "input": "A, 10 / B, 20",
      "expected": {
        "max": 20,
        "min": 10,
        "aLength": 0.5,
        "bLength": 1,
        "signs": [
          1,
          1
        ]
      },
      "actual": {
        "stats": {
          "count": 2,
          "max": 20,
          "min": 10,
          "avg": 15
        },
        "summary": "Count 2 · Max 20 · Min 10 · Avg 15.0",
        "lengths": [
          0.5,
          1
        ],
        "signs": [
          1,
          1
        ]
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc02-single-value",
      "kind": "golden",
      "input": "A, 10",
      "expected": "Single full-length bar",
      "actual": {
        "lengthFrac": 1,
        "max": 10
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc03-decimal",
      "kind": "golden",
      "input": "A, 1.5 / B, 2.75",
      "expected": {
        "aLength": 0.5454545454545454,
        "bLength": 1
      },
      "actual": {
        "lengths": [
          0.5454545454545454,
          1
        ]
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc04-zero-mixed",
      "kind": "boundary",
      "input": "A, 0 / B, 10",
      "expected": {
        "aLength": 0,
        "bLength": 1
      },
      "actual": {
        "lengths": [
          0,
          1
        ],
        "signs": [
          0,
          1
        ]
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc05-all-zero",
      "kind": "boundary",
      "input": "A, 0 / B, 0 / C, 0",
      "expected": {
        "lengths": [
          0,
          0,
          0
        ],
        "max": 0,
        "min": 0,
        "avg": 0,
        "domain": [
          0,
          1
        ],
        "noNaN": true
      },
      "actual": {
        "lengths": [
          0,
          0,
          0
        ],
        "stats": {
          "count": 3,
          "max": 0,
          "min": 0,
          "avg": 0
        },
        "scale": {
          "min": 0,
          "max": 1,
          "allZero": true
        },
        "finite": true
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc06-negative-only",
      "kind": "golden",
      "input": "A, -10 / B, -20",
      "expected": {
        "domain": [
          -20,
          0
        ],
        "grow": "down",
        "bLonger": true
      },
      "actual": {
        "scale": {
          "min": -20,
          "max": 0
        },
        "lengths": [
          0.5,
          1
        ],
        "grow": [
          "down",
          "down"
        ]
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc07-mixed-signed",
      "kind": "golden",
      "input": "A, -10 / B, 20",
      "expected": {
        "domain": [
          -10,
          20
        ],
        "aGrow": "down",
        "bGrow": "up",
        "notEqualLength": true
      },
      "actual": {
        "scale": {
          "min": -10,
          "max": 20,
          "zeroFrac": 0.3333333333333333
        },
        "lengths": [
          0.3333333333333333,
          0.6666666666666667
        ],
        "grow": [
          "down",
          "up"
        ]
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc08-horizontal-signed",
      "kind": "golden",
      "input": "A, 100 / B, -100 (vertical + horizontal)",
      "expected": {
        "equalLength": true,
        "vertical": [
          "up",
          "down"
        ],
        "horizontal": [
          "right",
          "left"
        ]
      },
      "actual": {
        "lengths": [
          0.5,
          0.5
        ],
        "vertical": [
          "up",
          "down"
        ],
        "horizontal": [
          "right",
          "left"
        ]
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc08b-axis-captions",
      "kind": "golden",
      "input": "Horizontal toggle with default vs custom axis labels",
      "expected": {
        "vertical": {
          "x": "Category",
          "y": "Value"
        },
        "horizontal": {
          "x": "Value",
          "y": "Category"
        },
        "customPreserved": true
      },
      "actual": {
        "v": {
          "xLabel": "Category",
          "yLabel": "Value"
        },
        "h": {
          "xLabel": "Value",
          "yLabel": "Category"
        },
        "swapped": {
          "xLabel": "Value",
          "yLabel": "Category"
        },
        "custom": {
          "xLabel": "Month",
          "yLabel": "USD"
        }
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc09-malformed-line",
      "kind": "boundary",
      "input": "A, foo / B, 10",
      "expected": {
        "pairs": [
          {
            "label": "B",
            "value": 10
          }
        ]
      },
      "actual": [
        {
          "label": "B",
          "value": 10
        }
      ],
      "passed": true,
      "ok": true
    },
    {
      "id": "tc10-empty",
      "kind": "boundary",
      "input": "(empty)",
      "expected": {
        "count": 0,
        "summary": ""
      },
      "actual": {
        "count": 0,
        "summary": ""
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc11-large-value",
      "kind": "boundary",
      "input": "A, 1e308",
      "expected": {
        "finite": true,
        "lengthFrac": 1
      },
      "actual": {
        "value": 1e+308,
        "max": 1e+308,
        "lengthFrac": 1
      },
      "passed": true,
      "ok": true
    },
    {
      "id": "tc12-sample-summary-ticks",
      "kind": "golden",
      "input": "Jan,12 … Jun,18",
      "expected": {
        "summary": "Count 6 · Max 22 · Min 8 · Avg 15.7",
        "ticksInclude": [
          0,
          20
        ]
      },
      "actual": {
        "summary": "Count 6 · Max 22 · Min 8 · Avg 15.7",
        "ticks": [
          0,
          5,
          10,
          15,
          20
        ]
      },
      "passed": true,
      "ok": true
    }
  ]
}
