Refactored errors for XYShape
This commit is contained in:
		
							parent
							
								
									95a4bac49b
								
							
						
					
					
						commit
						94d4a38540
					
				| 
						 | 
				
			
			@ -18,21 +18,22 @@ let pointSetDist3: PointSetTypes.xyShape = {
 | 
			
		|||
  ys: [0.2, 0.5, 0.8],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let makeAndGetErrorString = (~xs, ~ys) =>
 | 
			
		||||
  XYShape.T.make(~xs, ~ys)->E.R.getError->E.O2.fmap(XYShape.Error.toString)
 | 
			
		||||
 | 
			
		||||
describe("XYShapes", () => {
 | 
			
		||||
  describe("Validator", () => {
 | 
			
		||||
    makeTest("with no errors", XYShape.T.Validator.validate(pointSetDist1), None)
 | 
			
		||||
    makeTest(
 | 
			
		||||
      "when empty",
 | 
			
		||||
      XYShape.T.Validator.validate({xs: [], ys: []})->E.O2.fmap(Errors.toString),
 | 
			
		||||
      Some("XYShape validate Xs is empty"),
 | 
			
		||||
      "with no errors",
 | 
			
		||||
      makeAndGetErrorString(~xs=[1.0, 4.0, 8.0], ~ys=[0.2, 0.4, 0.8]),
 | 
			
		||||
      None,
 | 
			
		||||
    )
 | 
			
		||||
    makeTest("when empty", makeAndGetErrorString(~xs=[], ~ys=[]), Some("Xs is empty"))
 | 
			
		||||
    makeTest(
 | 
			
		||||
      "when not sorted, different lengths, and not finite",
 | 
			
		||||
      XYShape.T.Validator.validate({xs: [2.0, 1.0, infinity, 0.0], ys: [3.0, Js.Float._NaN]})->E.O2.fmap(
 | 
			
		||||
        Errors.toString,
 | 
			
		||||
      ),
 | 
			
		||||
      makeAndGetErrorString(~xs=[2.0, 1.0, infinity, 0.0], ~ys=[3.0, Js.Float._NaN]),
 | 
			
		||||
      Some(
 | 
			
		||||
        "Multiple Errors: [XYShape validate Xs is not sorted], [XYShape validate Xs and Ys have different lengths. Xs has length 4 and Ys has length 2], [XYShape validate Xs is not finite. Example value: Infinity], [XYShape validate Ys is not finite. Example value: NaN]",
 | 
			
		||||
        "Multiple Errors: [Xs is not sorted], [Xs and Ys have different lengths. Xs has length 4 and Ys has length 2], [Xs is not finite. Example value: Infinity], [Ys is not finite. Example value: NaN]",
 | 
			
		||||
      ),
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ type error =
 | 
			
		|||
  | RequestedStrategyInvalidError(string)
 | 
			
		||||
  | LogarithmOfDistributionError(string)
 | 
			
		||||
  | OtherError(string)
 | 
			
		||||
  | XYShapeError(XYShape.error)
 | 
			
		||||
 | 
			
		||||
@genType
 | 
			
		||||
module Error = {
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,7 @@ module Error = {
 | 
			
		|||
    | PointSetConversionError(err) => SampleSetDist.pointsetConversionErrorToString(err)
 | 
			
		||||
    | SparklineError(err) => PointSetTypes.sparklineErrorToString(err)
 | 
			
		||||
    | RequestedStrategyInvalidError(err) => `Requested strategy invalid: ${err}`
 | 
			
		||||
    | XYShapeError(err) => `XY Shape Error: ${XYShape.Error.toString(err)}`
 | 
			
		||||
    | OtherError(s) => s
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -162,6 +162,12 @@ exception Assertion(string)
 | 
			
		|||
module R = {
 | 
			
		||||
  let result = Rationale.Result.result
 | 
			
		||||
  let id = e => e |> result(U.id, U.id)
 | 
			
		||||
  let isOk = Belt.Result.isOk
 | 
			
		||||
  let getError = (r: result<'a, 'b>) =>
 | 
			
		||||
    switch r {
 | 
			
		||||
    | Ok(_) => None
 | 
			
		||||
    | Error(e) => Some(e)
 | 
			
		||||
    }
 | 
			
		||||
  let fmap = Rationale.Result.fmap
 | 
			
		||||
  let bind = Rationale.Result.bind
 | 
			
		||||
  let toExn = (msg: string, x: result<'a, 'b>): 'a =>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,31 +0,0 @@
 | 
			
		|||
type property = {fnName: string, propertyName: string}
 | 
			
		||||
 | 
			
		||||
type rec error =
 | 
			
		||||
  | NotSorted(property)
 | 
			
		||||
  | IsEmpty(property)
 | 
			
		||||
  | NotFinite(property, float)
 | 
			
		||||
  | DifferentLengths({fnName: string, p1Name: string, p2Name: string, p1Length: int, p2Length: int})
 | 
			
		||||
  | Multiple(array<error>)
 | 
			
		||||
 | 
			
		||||
let mapErrorArrayToError = (errors: array<error>): option<error> => {
 | 
			
		||||
  switch errors {
 | 
			
		||||
  | [] => None
 | 
			
		||||
  | [error] => Some(error)
 | 
			
		||||
  | _ => Some(Multiple(errors))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let rec toString = (t: error) =>
 | 
			
		||||
  switch t {
 | 
			
		||||
  | NotSorted({fnName, propertyName}) => `${fnName} ${propertyName} is not sorted`
 | 
			
		||||
  | IsEmpty({fnName, propertyName}) => `${fnName} ${propertyName} is empty`
 | 
			
		||||
  | NotFinite({fnName, propertyName}, exampleValue) =>
 | 
			
		||||
    `${fnName} ${propertyName} is not finite. Example value: ${E.Float.toString(exampleValue)}`
 | 
			
		||||
  | DifferentLengths({fnName, p1Name, p2Name, p1Length, p2Length}) =>
 | 
			
		||||
    `${fnName} ${p1Name} and ${p2Name} have different lengths. ${p1Name} has length ${E.I.toString(
 | 
			
		||||
        p1Length,
 | 
			
		||||
      )} and ${p2Name} has length ${E.I.toString(p2Length)}`
 | 
			
		||||
  | Multiple(errors) =>
 | 
			
		||||
    `Multiple Errors: ${E.A2.fmap(errors, toString)->E.A2.fmap(r => `[${r}]`)
 | 
			
		||||
        |> E.A.joinWith(", ")}`
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -4,6 +4,42 @@ type xyShape = {
 | 
			
		|||
  ys: array<float>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type propertyName = string
 | 
			
		||||
 | 
			
		||||
@genType
 | 
			
		||||
type rec error =
 | 
			
		||||
  | NotSorted(propertyName)
 | 
			
		||||
  | IsEmpty(propertyName)
 | 
			
		||||
  | NotFinite(propertyName, float)
 | 
			
		||||
  | DifferentLengths({p1Name: string, p2Name: string, p1Length: int, p2Length: int})
 | 
			
		||||
  | MultipleErrors(array<error>)
 | 
			
		||||
 | 
			
		||||
@genType
 | 
			
		||||
module Error = {
 | 
			
		||||
  let mapErrorArrayToError = (errors: array<error>): option<error> => {
 | 
			
		||||
    switch errors {
 | 
			
		||||
    | [] => None
 | 
			
		||||
    | [error] => Some(error)
 | 
			
		||||
    | _ => Some(MultipleErrors(errors))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let rec toString = (t: error) =>
 | 
			
		||||
    switch t {
 | 
			
		||||
    | NotSorted(propertyName) => `${propertyName} is not sorted`
 | 
			
		||||
    | IsEmpty(propertyName) => `${propertyName} is empty`
 | 
			
		||||
    | NotFinite(propertyName, exampleValue) =>
 | 
			
		||||
      `${propertyName} is not finite. Example value: ${E.Float.toString(exampleValue)}`
 | 
			
		||||
    | DifferentLengths({p1Name, p2Name, p1Length, p2Length}) =>
 | 
			
		||||
      `${p1Name} and ${p2Name} have different lengths. ${p1Name} has length ${E.I.toString(
 | 
			
		||||
          p1Length,
 | 
			
		||||
        )} and ${p2Name} has length ${E.I.toString(p2Length)}`
 | 
			
		||||
    | MultipleErrors(errors) =>
 | 
			
		||||
      `Multiple Errors: ${E.A2.fmap(errors, toString)->E.A2.fmap(r => `[${r}]`)
 | 
			
		||||
          |> E.A.joinWith(", ")}`
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@genType
 | 
			
		||||
type interpolationStrategy = [
 | 
			
		||||
  | #Stepwise
 | 
			
		||||
| 
						 | 
				
			
			@ -63,15 +99,10 @@ module T = {
 | 
			
		|||
 | 
			
		||||
  module Validator = {
 | 
			
		||||
    let fnName = "XYShape validate"
 | 
			
		||||
    let property = (propertyName: string): Errors.property => {
 | 
			
		||||
      fnName: fnName,
 | 
			
		||||
      propertyName: propertyName,
 | 
			
		||||
    }
 | 
			
		||||
    let notSortedError = (p: string): Errors.error => NotSorted(property(p))
 | 
			
		||||
    let notFiniteError = (p, exampleValue): Errors.error => NotFinite(property(p), exampleValue)
 | 
			
		||||
    let isEmptyError = (propertyName): Errors.error => IsEmpty(property(propertyName))
 | 
			
		||||
    let differentLengthsError = (t): Errors.error => DifferentLengths({
 | 
			
		||||
      fnName: fnName,
 | 
			
		||||
    let notSortedError = (p: string): error => NotSorted(p)
 | 
			
		||||
    let notFiniteError = (p, exampleValue): error => NotFinite(p, exampleValue)
 | 
			
		||||
    let isEmptyError = (propertyName): error => IsEmpty(propertyName)
 | 
			
		||||
    let differentLengthsError = (t): error => DifferentLengths({
 | 
			
		||||
      p1Name: "Xs",
 | 
			
		||||
      p2Name: "Ys",
 | 
			
		||||
      p1Length: E.A.length(xs(t)),
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +123,15 @@ module T = {
 | 
			
		|||
      let ysNotFinite = getNonFiniteYs(t)->E.O2.fmap(notFiniteError("Ys"))
 | 
			
		||||
      [xsNotSorted, xsEmpty, differentLengths, xsNotFinite, ysNotFinite]
 | 
			
		||||
      ->E.A.O.concatSomes
 | 
			
		||||
      ->Errors.mapErrorArrayToError
 | 
			
		||||
      ->Error.mapErrorArrayToError
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let make = (~xs: array<float>, ~ys: array<float>) => {
 | 
			
		||||
    let attempt: t = {xs: xs, ys: ys}
 | 
			
		||||
    switch Validator.validate(attempt) {
 | 
			
		||||
    | Some(error) => Error(error)
 | 
			
		||||
    | None => Ok(attempt)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user