Skip to content

Commit

Permalink
Add error handling when data file length does not match spec
Browse files Browse the repository at this point in the history
  • Loading branch information
rexcfnghk committed Jun 9, 2024
1 parent 5fbdb92 commit 20a4ee3
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 11 deletions.
3 changes: 2 additions & 1 deletion DataParser.Console/Core.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ type Error =
| DataFileNameFormatError of fileName: string
| UnexpectedFormatHeader of string
| UnexpectedFormatLine of string
| UnparsableValue of obj
| UnparsableValue of string
| DataFileLineLengthShorterThanSpec of string
| UnparsableFormatFile of fileContent: string

let (<*>) f x =
Expand Down
44 changes: 34 additions & 10 deletions DataParser.Console/DataFiles.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,43 @@ let getDataFileFormat (fileFormatLookup: Map<FormatName, FormatLine list>) (file
let parseDataFileLine (formatLines : FormatLine list) (dataFileLine : string) : Result<JsonObject, Error list> =
let parseDataType dataType (s: byte array) : Result<obj, Error list> =
match dataType with
| JBool -> if s = [|TrueByte|] then Ok true elif s = [|FalseByte|] then Ok false else Error [UnparsableValue s]
| JInt -> match System.Int32.TryParse (s, CultureInfo.InvariantCulture) with true, i -> Ok i | false, _ -> Error [UnparsableValue s]
| JString -> Ok <| let result = Encoding.UTF8.GetString s in result.Trim()
| JBool ->
if s = [|TrueByte|]
then Ok true
elif s = [|FalseByte|]
then Ok false
else
let errorValue = Encoding.UTF8.GetString s
Error [UnparsableValue errorValue]
| JInt ->
match System.Int32.TryParse (s, CultureInfo.InvariantCulture) with
| true, i -> Ok i
| false, _ ->
let errorValue = Encoding.UTF8.GetString s
Error [UnparsableValue errorValue]
| JString ->
let result = Encoding.UTF8.GetString s
Ok <| result.Trim()

let folder (stream : MemoryStream, map) (FormatLine (columnName, width, dataType)) =
let byteArray = Array.create width 0uy
stream.ReadExactly(byteArray, 0, width)
let result = parseDataType dataType byteArray
stream, Map.add columnName result map
let folder result (FormatLine (columnName, width, dataType)) =
match result with
| Error e -> Error e
| Ok (stream : MemoryStream, map) ->
let byteArray = Array.create width 0uy
try
stream.ReadExactly(byteArray, 0, width)
let result = parseDataType dataType byteArray
Ok (stream, Map.add columnName result map)
with
| :? EndOfStreamException ->
let line = Encoding.UTF8.GetString (stream.ToArray())
Error [DataFileLineLengthShorterThanSpec line]

let bytes : byte array = Encoding.UTF8.GetBytes dataFileLine
use s = new MemoryStream(bytes)
let _, map = List.fold folder (s, Map.empty) formatLines
let initialState = Ok (s, Map.empty)
let map =
List.fold folder initialState formatLines
|> Result.bind (mapSequenceResult << snd)

map
|> mapSequenceResult
12 changes: 12 additions & 0 deletions DataParser.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ let ``Given a format and a dataFileLine of Diabetes, parseDataFileLine returns a

parseDataFileLine formatLines dataFileLine =! expected

[<Xunit.Fact>]
let ``Given a format and a dataFileLine shorter than format width, parseDataFileLine returns an Error`` () =
let dataFileLine = "Diabetes 1 1\n"
let formatLines = [
FormatLine ("name", 10, JsonDataType.JString)
FormatLine ("valid", 1, JsonDataType.JBool)
FormatLine("count", 3, JsonDataType.JInt)
]
let expected : Result<JsonObject, Error list> = Error [DataFileLineLengthShorterThanSpec dataFileLine]

parseDataFileLine formatLines dataFileLine =! expected

[<Xunit.Fact>]
let ``Given a format and a dataFileLine of Asthma, parseDataFileLine returns an expected map`` () =
let dataFileLine = "Asthma 0-14\n"
Expand Down

0 comments on commit 20a4ee3

Please sign in to comment.