{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://stryker-mutator.io/report.schema.json",
  "title": "MutationTestResult",
  "description": "Schema for a mutation testing report.",
  "type": "object",
  "required": ["schemaVersion", "thresholds", "files"],
  "properties": {
    "config": {
      "description": "Free-format object that represents the configuration used to run mutation testing.",
      "type": "object"
    },
    "schemaVersion": {
      "type": "string",
      "pattern": "^([1-2])(\\.(([1-9]\\d*)|0)){0,2}$",
      "description": "Major version of this report. Used for compatibility.",
      "examples": ["1", "2.0", "2.0.0"]
    },
    "files": {
      "type": "object",
      "title": "FileResultDictionary",
      "description": "All mutated files.",
      "additionalProperties": {
        "type": "object",
        "title": "FileResult",
        "description": "Mutated file, with the relative path of the file as the key.",
        "required": ["language", "source", "mutants"],
        "properties": {
          "language": {
            "description": "Programming language that is used. Used for code highlighting, see https://prismjs.com/#examples.",
            "examples": ["javascript", "typescript", "cs", "scala", "java"],
            "type": "string"
          },
          "mutants": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "object",
              "title": "MutantResult",
              "description": "Single mutation.",
              "required": ["id", "mutatorName", "location", "status"],
              "properties": {
                "coveredBy": {
                  "type": "array",
                  "description": "The test ids that covered this mutant. If a mutation testing framework doesn't measure this information, it can simply be left out.",
                  "items": {
                    "type": "string"
                  }
                },
                "description": {
                  "type": "string",
                  "description": "Description of the applied mutation.",
                  "examples": ["removed call to java/io/Writer::write"]
                },
                "duration": {
                  "type": "number",
                  "description": "The net time it took to test this mutant in milliseconds. This is the time measurement without overhead from the mutation testing framework."
                },
                "id": {
                  "type": "string",
                  "description": "Unique id, can be used to correlate this mutant across reports.",
                  "examples": ["321321"]
                },
                "killedBy": {
                  "type": "array",
                  "description": "The test ids that killed this mutant. It is a best practice to \"bail\" on first failing test, in which case you can fill this array with that one test.",
                  "items": {
                    "type": "string"
                  }
                },
                "location": {
                  "$ref": "#/definitions/location"
                },
                "mutatorName": {
                  "type": "string",
                  "description": "Category of the mutation.",
                  "examples": ["ConditionalExpression", "EqualityOperator", "LogicalOperator"]
                },
                "replacement": {
                  "type": "string",
                  "description": "Actual mutation that has been applied.",
                  "examples": ["-", "+", "&&", "||"]
                },
                "static": {
                  "type": "boolean",
                  "description": "A static mutant means that it was loaded once at during initialization, this makes it slow or even impossible to test, depending on the mutation testing framework."
                },
                "status": {
                  "type": "string",
                  "title": "MutantStatus",
                  "description": "Result of the mutation.",
                  "enum": ["Killed", "Survived", "NoCoverage", "CompileError", "RuntimeError", "Timeout", "Ignored", "Pending"]
                },
                "statusReason": {
                  "type": "string",
                  "description": "The reason that this mutant has this status. In the case of a killed mutant, this should be filled with the failure message(s) of the failing tests. In case of an error mutant, this should be filled with the error message."
                },
                "testsCompleted": {
                  "type": "number",
                  "description": "The number of tests actually completed in order to test this mutant. Can differ from \"coveredBy\" because of bailing a mutant test run after first failing test."
                }
              }
            }
          },
          "source": {
            "description": "Full source code of the original file (without mutants), this is used to display exactly what was changed for each mutant.",
            "examples": ["using System; using....."],
            "type": "string"
          }
        }
      }
    },
    "testFiles": {
      "type": "object",
      "title": "TestFileDefinitionDictionary",
      "description": "Test file definitions by file path OR class name.",
      "additionalProperties": {
        "type": "object",
        "title": "TestFile",
        "description": "A file containing one or more tests",
        "required": ["tests"],
        "properties": {
          "source": {
            "description": "Full source code of the test file, this can be used to display in the report.",
            "type": "string"
          },
          "tests": {
            "type": "array",
            "items": {
              "type": "object",
              "title": "TestDefinition",
              "required": ["id", "name"],
              "description": "A test in your test file.",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Unique id of the test, used to correlate what test killed a mutant."
                },
                "name": {
                  "type": "string",
                  "description": "Name of the test, used to display the test."
                },
                "location": {
                  "$ref": "#/definitions/openEndLocation"
                }
              }
            }
          }
        }
      }
    },
    "thresholds": {
      "type": "object",
      "title": "Thresholds",
      "description": "Thresholds for the status of the reported application.",
      "required": ["high", "low"],
      "properties": {
        "high": {
          "type": "integer",
          "description": "Higher bound threshold.",
          "minimum": 0,
          "maximum": 100,
          "examples": [80]
        },
        "low": {
          "type": "integer",
          "description": "Lower bound threshold.",
          "minimum": 0,
          "maximum": 100,
          "examples": [60]
        }
      }
    },
    "projectRoot": {
      "type": "string",
      "description": "The optional location of the project root.",
      "examples": ["C:\\Projects\\project-under-test", "/home/user/projects/project-under-test"]
    },
    "performance": {
      "type": "object",
      "title": "PerformanceStatistics",
      "description": "The performance statistics per phase. Total time should be roughly equal to the sum of all these.",
      "required": ["setup", "initialRun", "mutation"],
      "properties": {
        "setup": {
          "type": "number",
          "description": "Time it took to run the setup phase in milliseconds."
        },
        "initialRun": {
          "type": "number",
          "description": "Time it took to run the initial test phase (dry-run) in milliseconds."
        },
        "mutation": {
          "type": "number",
          "description": "Time it took to run the mutation test phase in milliseconds."
        }
      }
    },
    "framework": {
      "type": "object",
      "title": "FrameworkInformation",
      "description": "Extra information about the framework used",
      "required": ["name"],
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of the framework used.",
          "examples": ["Stryker", "Stryker4s", "Stryker.NET", "Infection PHP", "Pitest"]
        },
        "version": {
          "type": "string",
          "description": "Version of the framework."
        },
        "branding": {
          "type": "object",
          "title": "BrandingInformation",
          "description": "Extra branding information about the framework used.",
          "required": ["homepageUrl"],
          "properties": {
            "homepageUrl": {
              "type": "string",
              "format": "uri",
              "description": "URL to the homepage of the framework."
            },
            "imageUrl": {
              "type": "string",
              "description": "URL to an image for the framework, can be a data URL."
            }
          }
        },
        "dependencies": {
          "type": "object",
          "title": "Dependencies",
          "description": "Dependencies used by the framework. Key-value pair of dependencies and their versions.",
          "additionalProperties": {
            "type": "string"
          }
        }
      }
    },
    "system": {
      "type": "object",
      "title": "SystemInformation",
      "description": "Information about the system that performed mutation testing.",
      "required": ["ci"],
      "properties": {
        "ci": {
          "description": "Did mutation testing run in a Continuous Integration environment (pipeline)? Note that there is no way of knowing this for sure. It's done on a best-effort basis.",
          "type": "boolean"
        },
        "os": {
          "type": "object",
          "title": "OSInformation",
          "required": ["platform"],
          "properties": {
            "description": {
              "type": "string",
              "description": "Human-readable description of the OS",
              "examples": ["Windows 10 Pro", "Debian Buster", "Ubuntu 20.04.1 LTS"]
            },
            "platform": {
              "type": "string",
              "description": "Platform identifier",
              "examples": ["linux", "win32"]
            },
            "version": {
              "type": "string",
              "description": "Version of the OS or distribution",
              "examples": ["10.0.19041"]
            }
          }
        },
        "cpu": {
          "type": "object",
          "title": "CpuInformation",
          "required": ["logicalCores"],
          "properties": {
            "baseClock": {
              "type": "number",
              "description": "Clock speed in MHz"
            },
            "logicalCores": {
              "type": "number"
            },
            "model": {
              "type": "string",
              "examples": ["Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz"]
            }
          }
        },
        "ram": {
          "title": "RamInformation",
          "type": "object",
          "required": ["total"],
          "properties": {
            "total": {
              "type": "number",
              "description": "The total RAM of the system that performed mutation testing in MB."
            }
          }
        }
      }
    }
  },
  "definitions": {
    "position": {
      "type": "object",
      "title": "Position",
      "description": "Position of a mutation. Both line and column start at one.",
      "required": ["line", "column"],
      "properties": {
        "line": {
          "type": "integer",
          "minimum": 1,
          "examples": [4]
        },
        "column": {
          "type": "integer",
          "minimum": 1,
          "examples": [3]
        }
      }
    },
    "location": {
      "type": "object",
      "title": "Location",
      "description": "A location with start and end. Start is inclusive, end is exclusive.",
      "required": ["start", "end"],
      "properties": {
        "start": {
          "$ref": "#/definitions/position"
        },
        "end": {
          "$ref": "#/definitions/position"
        }
      }
    },
    "openEndLocation": {
      "type": "object",
      "title": "OpenEndLocation",
      "description": "A location where \"end\" is not required. Start is inclusive, end is exclusive.",
      "required": ["start"],
      "properties": {
        "start": {
          "$ref": "#/definitions/position"
        },
        "end": {
          "$ref": "#/definitions/position"
        }
      }
    }
  }
}
