
test_that("a known-good lockfile passes validation", {
  
  skip_on_cran()
  skip_if_not_installed("jsonvalidate")
  
  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      },
      {
        "Name": "BioCsoft",
        "URL": "https://bioconductor.org/packages/3.8/bioc"
      }
    ]
  },
  "Python": {
    "Version": "3.10.12",
    "Type": "virtualenv",
    "Name": "./renv/python/virtualenvs/renv-python-3.10"
  },
  "Bioconductor": {
    "Version": "3.8"
  },
  "Packages": {
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd7987d59dda3a02cfb41"
    },
    "mime": {
      "Package": "mime",
      "Version": "0.12.1",
      "Source": "GitHub",
      "RemoteType": "github",
      "RemoteHost": "api.github.com",
      "RemoteUsername": "yihui",
      "RemoteRepo": "mime",
      "RemoteRef": "main",
      "RemoteSha": "1763e0dcb72fb58d97bab97bb834fc71f1e012bc",
      "Requirements": [
        "tools"
      ],
      "Hash": "c2772b6269924dad6784aaa1d99dbb86"
    }
  }
}
'
  expect_no_error(lockfile_validate(lockfile = lockfile))
  expect_true(lockfile_validate(lockfile = lockfile))
  
})


test_that("a known-good lockfile with extra fields passes validation", {

  skip_on_cran()
  skip_if_not_installed("jsonvalidate")

  # Lockfile adds a R$Nickname field not present in the schema
  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Nickname": "Shortstop Beagle",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      },
      {
        "Name": "BioCsoft",
        "URL": "https://bioconductor.org/packages/3.8/bioc"
      }
    ]
  },
  "Python": {
    "Version": "3.10.12",
    "Type": "virtualenv",
    "Name": "./renv/python/virtualenvs/renv-python-3.10"
  },
  "Bioconductor": {
    "Version": "3.8"
  },
  "Packages": {
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd7987d59dda3a02cfb41"
    },
    "mime": {
      "Package": "mime",
      "Version": "0.12.1",
      "Source": "GitHub",
      "RemoteType": "github",
      "RemoteHost": "api.github.com",
      "RemoteUsername": "yihui",
      "RemoteRepo": "mime",
      "RemoteRef": "main",
      "RemoteSha": "1763e0dcb72fb58d97bab97bb834fc71f1e012bc",
      "Requirements": [
        "tools"
      ],
      "Hash": "c2772b6269924dad6784aaa1d99dbb86"
    }
  }
}
'
  expect_no_error(lockfile_validate(lockfile = lockfile))
  expect_true(lockfile_validate(lockfile = lockfile))
  
})

test_that("a custom schema file can be used for successful validation", {

  skip_on_cran()
  skip_if_not_installed("jsonvalidate")

  # Custom schema adds a required R$Nickname field present in the lockfile
  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Nickname": "Shortstop Beagle",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      }
    ]
  },
  "Packages": {
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd7987d59dda3a02cfb41"
    }
  }
}
'

  schema <- '
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "R": {
      "type": "object",
      "properties": {
        "Version": {
          "type": "string"
        },
        "Nickname": {
          "type": "string"
        }
      },
      "required": ["Version", "Nickname"]
    }
  }
}
'
  expect_no_error(lockfile_validate(lockfile = lockfile, schema = schema))
  expect_true(lockfile_validate(lockfile = lockfile, schema = schema))
  
})

test_that("a custom schema file can be used for failed validation", {

  skip_on_cran()
  skip_if_not_installed("jsonvalidate")

  # Custom schema adds a required R$Nickname field not present in the lockfile
  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      }
    ]
  },
  "Packages": {
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd7987d59dda3a02cfb41"
    }
  }
}
'

  schema <- '
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "R": {
      "type": "object",
      "properties": {
        "Version": {
          "type": "string"
        },
        "Nickname": {
          "type": "string"
        }
      },
      "required": ["Version", "Nickname"]
    }
  }
}
'

  expect_false(lockfile_validate(lockfile = lockfile, schema = schema))
  
})

test_that("an incorrect Packages$Hash field fails validation", {

  skip_on_cran()
  skip_if_not_installed("jsonvalidate")

  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      }
    ]
  },
  "Packages": {
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd"
    }
  }
}
'

  expect_false(lockfile_validate(lockfile = lockfile))
  
})

test_that("invalid JSON fails validation", {

  skip_on_cran()
  skip_if_not_installed("jsonvalidate")

  # Packages uses [] which is not valid JSON
  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      }
    ]
  },
  "Packages": [
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd7987d59dda3a02cfb41"
    }
  ]
}
'
  expect_error(lockfile_validate(lockfile = lockfile, error = TRUE))
  
})

test_that("strict mode catches unknown keyword in provided schema", {

  skip_on_cran()
  skip_if_not_installed("jsonvalidate")

  # Custom schema provides "Version" with "type": "UNKNOWN"
  lockfile <- '
{
  "R": {
    "Version": "4.2.3",
    "Repositories": [
      {
        "Name": "CRAN",
        "URL": "https://cloud.r-project.org"
      }
    ]
  },
  "Packages": {
    "markdown": {
      "Package": "markdown",
      "Version": "1.0",
      "Source": "Repository",
      "Repository": "CRAN",
      "Hash": "4584a57f565dd7987d59dda3a02cfb41"
    }
  }
}
'

  schema <- '
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "R": {
      "type": "object",
      "properties": {
        "Version": {
          "UNKNOWN": "string"
        }
      }
    }
  }
}
'
  expect_true(lockfile_validate(lockfile = lockfile, schema = schema))
  expect_error(lockfile_validate(lockfile = lockfile, schema = schema, strict = TRUE))
  
})
