mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
merge main, update fail test descriptions
This commit is contained in:
parent
e5dd4295c9
commit
addc4debef
11 changed files with 1822 additions and 1855 deletions
|
@ -405,13 +405,11 @@ decodeBool = Decode.custom \bytes, @Json {} ->
|
|||
_ -> { result: Err TooShort, rest: bytes }
|
||||
|
||||
expect
|
||||
actual : DecodeResult Bool
|
||||
actual = "true\n" |> Str.toUtf8 |> Decode.fromBytesPartial fromUtf8
|
||||
expected = Ok Bool.true
|
||||
actual.result == expected
|
||||
|
||||
expect
|
||||
actual : DecodeResult Bool
|
||||
actual = "false ]\n" |> Str.toUtf8 |> Decode.fromBytesPartial fromUtf8
|
||||
expected = Ok Bool.false
|
||||
actual.result == expected
|
||||
|
@ -459,12 +457,6 @@ parseExactChar = \bytes, char ->
|
|||
|
||||
Err _ -> { result: Err TooShort, rest: bytes }
|
||||
|
||||
# openBrace : List U8 -> DecodeResult {}
|
||||
# openBrace = \bytes -> parseExactChar bytes '{'
|
||||
|
||||
# closingBrace : List U8 -> DecodeResult {}
|
||||
# closingBrace = \bytes -> parseExactChar bytes '}'
|
||||
|
||||
openBracket : List U8 -> DecodeResult {}
|
||||
openBracket = \bytes -> parseExactChar bytes '['
|
||||
|
||||
|
@ -474,9 +466,6 @@ closingBracket = \bytes -> parseExactChar bytes ']'
|
|||
anything : List U8 -> DecodeResult {}
|
||||
anything = \bytes -> { result: Err TooShort, rest: bytes }
|
||||
|
||||
# colon : List U8 -> DecodeResult {}
|
||||
# colon = \bytes -> parseExactChar bytes ':'
|
||||
|
||||
comma : List U8 -> DecodeResult {}
|
||||
comma = \bytes -> parseExactChar bytes ','
|
||||
|
||||
|
@ -588,10 +577,8 @@ expect
|
|||
expected = { result: Ok 2u64, rest: [']'] }
|
||||
actual == expected
|
||||
|
||||
# TODO why is this trying to decode as a Record?
|
||||
# If you use Decode.fromBytesPartial it fails
|
||||
expect
|
||||
actual = "30,\n" |> Str.toUtf8 |> Decode.decodeWith decodeI64 fromUtf8
|
||||
actual = "30,\n" |> Str.toUtf8 |> Decode.fromBytesPartial fromUtf8
|
||||
expected = { result: Ok 30i64, rest: [',', '\n'] }
|
||||
actual == expected
|
||||
|
||||
|
@ -1077,161 +1064,141 @@ expect
|
|||
|
||||
# JSON OBJECTS -----------------------------------------------------------------
|
||||
|
||||
# decodeRecord = \initialState, stepField, finalizer -> Decode.custom \bytes, @Json {} ->
|
||||
# # NB: the stepper function must be passed explicitly until #2894 is resolved.
|
||||
# decodeFields = \stepper, state, kvBytes ->
|
||||
# { val: key, rest } <- (Decode.decodeWith kvBytes decodeString (@Json {})) |> tryDecode
|
||||
# { rest: afterColonBytes } <- colon rest |> tryDecode
|
||||
# { val: newState, rest: beforeCommaOrBreak } <- tryDecode
|
||||
# (
|
||||
# when stepper state key is
|
||||
# Skip ->
|
||||
# { rest: beforeCommaOrBreak } <- afterColonBytes |> anything |> tryDecode
|
||||
# { result: Ok state, rest: beforeCommaOrBreak }
|
||||
|
||||
# Keep decoder ->
|
||||
# Decode.decodeWith afterColonBytes decoder (@Json {})
|
||||
# )
|
||||
|
||||
# { result: commaResult, rest: nextBytes } = comma beforeCommaOrBreak
|
||||
|
||||
# when commaResult is
|
||||
# Ok {} -> decodeFields stepField newState nextBytes
|
||||
# Err _ -> { result: Ok newState, rest: nextBytes }
|
||||
|
||||
# { rest: afterBraceBytes } <- bytes |> openBrace |> tryDecode
|
||||
|
||||
# { val: endStateResult, rest: beforeClosingBraceBytes } <- decodeFields stepField initialState afterBraceBytes |> tryDecode
|
||||
|
||||
# { rest: afterRecordBytes } <- beforeClosingBraceBytes |> closingBrace |> tryDecode
|
||||
|
||||
# when finalizer endStateResult is
|
||||
# Ok val -> { result: Ok val, rest: afterRecordBytes }
|
||||
# Err e -> { result: Err e, rest: afterRecordBytes }
|
||||
|
||||
decodeRecord = \initialState, stepField, finalizer -> Decode.custom \bytes, @Json {} ->
|
||||
|
||||
# Recursively build up record from object field:value pairs
|
||||
decodeFields = \recordState, bytesBeforeField ->
|
||||
# Recursively build up record from object field:value pairs
|
||||
decodeFields = \recordState, bytesBeforeField ->
|
||||
|
||||
# Decode the json string field name
|
||||
{result: fieldNameResult, rest: bytesAfterField} =
|
||||
Decode.decodeWith bytesBeforeField decodeString fromUtf8
|
||||
# Decode the json string field name
|
||||
{ result: fieldNameResult, rest: bytesAfterField } =
|
||||
Decode.decodeWith bytesBeforeField decodeString fromUtf8
|
||||
|
||||
# Count the bytes until the field value
|
||||
countBytesBeforeValue = when List.walkUntil bytesAfterField (BeforeColon 0) objectHelp is
|
||||
ObjectValueStart n -> n
|
||||
_ -> 0
|
||||
# Count the bytes until the field value
|
||||
countBytesBeforeValue =
|
||||
when List.walkUntil bytesAfterField (BeforeColon 0) objectHelp is
|
||||
AfterColon n -> n
|
||||
_ -> 0
|
||||
|
||||
valueBytes = List.drop bytesAfterField countBytesBeforeValue
|
||||
valueBytes = List.drop bytesAfterField countBytesBeforeValue
|
||||
|
||||
when fieldNameResult is
|
||||
Err TooShort ->
|
||||
# Invalid object, unable to decode field name or find colon ':'
|
||||
# after field and before the value
|
||||
{result: Err TooShort, rest: bytes}
|
||||
Ok fieldName ->
|
||||
# Decode the json value
|
||||
{val: updatedRecord, rest: bytesAfterValue } <-
|
||||
(
|
||||
# Retrieve value decoder for the current field
|
||||
when stepField recordState fieldName is
|
||||
Skip ->
|
||||
# TODO This doesn't seem right, shouldn't we eat
|
||||
# the remaining value bytes if we are skipping this
|
||||
# field?
|
||||
#
|
||||
# Should rest be bytesAfterNextValue or similar?
|
||||
{result: Ok recordState, rest: valueBytes}
|
||||
when fieldNameResult is
|
||||
Err TooShort ->
|
||||
# Invalid object, unable to decode field name or find colon ':'
|
||||
# after field and before the value
|
||||
{ result: Err TooShort, rest: bytes }
|
||||
|
||||
Keep valueDecoder ->
|
||||
# Decode the value using the decoder from the recordState
|
||||
Decode.decodeWith valueBytes valueDecoder fromUtf8
|
||||
)
|
||||
|> tryDecode
|
||||
Ok fieldName ->
|
||||
# Decode the json value
|
||||
{ val: updatedRecord, rest: bytesAfterValue } <-
|
||||
(
|
||||
# Retrieve value decoder for the current field
|
||||
when stepField recordState fieldName is
|
||||
Skip ->
|
||||
# TODO This doesn't seem right, shouldn't we eat
|
||||
# the remaining value bytes if we are skipping this
|
||||
# field?
|
||||
#
|
||||
# Should rest be bytesAfterNextValue or similar?
|
||||
{ result: Ok recordState, rest: valueBytes }
|
||||
|
||||
# Check if another field or '}' for end of object
|
||||
when List.walkUntil bytesAfterValue (AfterObjectValue 0) objectHelp is
|
||||
ObjectFieldNameStart n ->
|
||||
rest = List.drop bytesAfterValue n
|
||||
Keep valueDecoder ->
|
||||
# Decode the value using the decoder from the recordState
|
||||
Decode.decodeWith valueBytes valueDecoder fromUtf8
|
||||
)
|
||||
|> tryDecode
|
||||
|
||||
# Decode the next field and value
|
||||
decodeFields updatedRecord rest
|
||||
# Check if another field or '}' for end of object
|
||||
when List.walkUntil bytesAfterValue (AfterObjectValue 0) objectHelp is
|
||||
ObjectFieldNameStart n ->
|
||||
rest = List.drop bytesAfterValue n
|
||||
|
||||
AfterClosingBrace n ->
|
||||
rest = List.drop bytesAfterValue n
|
||||
# Decode the next field and value
|
||||
decodeFields updatedRecord rest
|
||||
|
||||
# Build final record from decoded fields and values
|
||||
when finalizer updatedRecord is
|
||||
Ok val -> { result: Ok val, rest }
|
||||
Err e -> { result: Err e, rest }
|
||||
AfterClosingBrace n ->
|
||||
rest = List.drop bytesAfterValue n
|
||||
|
||||
_ ->
|
||||
# Invalid object
|
||||
{result : Err TooShort, rest: bytesAfterValue}
|
||||
|
||||
|
||||
countBytesBeforeFirstField =
|
||||
when List.walkUntil bytes (BeforeOpeningBrace 0) objectHelp is
|
||||
ObjectFieldNameStart n -> n
|
||||
_ -> 0
|
||||
# Build final record from decoded fields and values
|
||||
when finalizer updatedRecord is
|
||||
Ok val -> { result: Ok val, rest }
|
||||
Err e -> { result: Err e, rest }
|
||||
|
||||
if countBytesBeforeFirstField == 0 then
|
||||
# Invalid object, expected opening brace '{' followed by a field
|
||||
{result: Err TooShort, rest: bytes}
|
||||
else
|
||||
bytesBeforeFirstField = (List.drop bytes countBytesBeforeFirstField)
|
||||
_ ->
|
||||
# Invalid object
|
||||
{ result: Err TooShort, rest: bytesAfterValue }
|
||||
|
||||
# Begin decoding field:value pairs
|
||||
decodeFields initialState bytesBeforeFirstField
|
||||
countBytesBeforeFirstField =
|
||||
when List.walkUntil bytes (BeforeOpeningBrace 0) objectHelp is
|
||||
ObjectFieldNameStart n -> n
|
||||
_ -> 0
|
||||
|
||||
if countBytesBeforeFirstField == 0 then
|
||||
# Invalid object, expected opening brace '{' followed by a field
|
||||
{ result: Err TooShort, rest: bytes }
|
||||
else
|
||||
bytesBeforeFirstField = List.drop bytes countBytesBeforeFirstField
|
||||
|
||||
# Begin decoding field:value pairs
|
||||
decodeFields initialState bytesBeforeFirstField
|
||||
|
||||
objectHelp : ObjectState, U8 -> [Break ObjectState, Continue ObjectState]
|
||||
objectHelp = \state, byte ->
|
||||
when (state, byte) is
|
||||
(BeforeOpeningBrace n, b) if isWhitespace b -> Continue (BeforeOpeningBrace (n+1))
|
||||
(BeforeOpeningBrace n, b) if b == '{' -> Continue (AfterOpeningBrace (n+1))
|
||||
(AfterOpeningBrace n, b) if isWhitespace b -> Continue (AfterOpeningBrace (n+1))
|
||||
when (state, byte) is
|
||||
(BeforeOpeningBrace n, b) if isWhitespace b -> Continue (BeforeOpeningBrace (n + 1))
|
||||
(BeforeOpeningBrace n, b) if b == '{' -> Continue (AfterOpeningBrace (n + 1))
|
||||
(AfterOpeningBrace n, b) if isWhitespace b -> Continue (AfterOpeningBrace (n + 1))
|
||||
(AfterOpeningBrace n, b) if b == '"' -> Break (ObjectFieldNameStart n) # field names must be a json string
|
||||
(BeforeColon n, b) if isWhitespace b -> Continue (BeforeColon (n+1))
|
||||
(BeforeColon n, b) if b == ':' -> Continue (AfterColon (n+1))
|
||||
(AfterColon n, b) if isWhitespace b -> Continue (AfterColon (n+1))
|
||||
(AfterColon n, _) -> Break (ObjectValueStart n) # object value could start with **almost** anything
|
||||
(AfterObjectValue n, b) if isWhitespace b -> Continue (AfterObjectValue (n+1))
|
||||
(AfterObjectValue n, b) if b == ',' -> Continue (AfterComma (n+1))
|
||||
(AfterObjectValue n, b) if b == '}' -> Continue (AfterClosingBrace (n+1))
|
||||
(AfterComma n, b) if isWhitespace b -> Continue (AfterComma (n+1))
|
||||
(BeforeColon n, b) if isWhitespace b -> Continue (BeforeColon (n + 1))
|
||||
(BeforeColon n, b) if b == ':' -> Continue (AfterColon (n + 1))
|
||||
(AfterColon n, b) if isWhitespace b -> Continue (AfterColon (n + 1))
|
||||
(AfterColon n, _) -> Break (AfterColon n) # object value could start with lots of things
|
||||
(AfterObjectValue n, b) if isWhitespace b -> Continue (AfterObjectValue (n + 1))
|
||||
(AfterObjectValue n, b) if b == ',' -> Continue (AfterComma (n + 1))
|
||||
(AfterObjectValue n, b) if b == '}' -> Continue (AfterClosingBrace (n + 1))
|
||||
(AfterComma n, b) if isWhitespace b -> Continue (AfterComma (n + 1))
|
||||
(AfterComma n, b) if b == '"' -> Break (ObjectFieldNameStart n)
|
||||
(AfterClosingBrace n, b) if isWhitespace b -> Continue (AfterClosingBrace (n+1))
|
||||
(AfterClosingBrace n, b) if isWhitespace b -> Continue (AfterClosingBrace (n + 1))
|
||||
_ -> Break InvalidObject
|
||||
|
||||
ObjectState : [
|
||||
BeforeOpeningBrace Nat,
|
||||
AfterOpeningBrace Nat,
|
||||
ObjectFieldNameStart Nat,
|
||||
BeforeColon Nat,
|
||||
AfterColon Nat,
|
||||
ObjectValueStart Nat,
|
||||
BeforeColon Nat,
|
||||
AfterColon Nat,
|
||||
AfterObjectValue Nat,
|
||||
AfterComma Nat,
|
||||
AfterClosingBrace Nat,
|
||||
AfterClosingBrace Nat,
|
||||
InvalidObject,
|
||||
]
|
||||
|
||||
# Test decode of simple Json Object into Roc Record
|
||||
expect
|
||||
input = Str.toUtf8 "{\"fruit\":2\n} "
|
||||
|
||||
actual = Decode.fromBytesPartial input fromUtf8
|
||||
expected = Ok { fruit: 2 }
|
||||
|
||||
actual.result == expected
|
||||
|
||||
# Test decode of simple Json Object into Roc Record
|
||||
# TODO assertion failed: value == 0 || value == 1
|
||||
# Test decode of simple Json Object into Roc Record ignoring whitespace
|
||||
# TODO this test makes `decodeI64` test fail
|
||||
# expect
|
||||
# input = Str.toUtf8 "{\"fruit\":\"two\"}"
|
||||
# input = Str.toUtf8 " {\n\"fruit\"\t:2\n } "
|
||||
|
||||
# actual = Decode.fromBytesPartial input fromUtf8
|
||||
# expected = Ok { fruit: "two" }
|
||||
# expected = Ok { fruit: 2 }
|
||||
|
||||
# actual.result == expected
|
||||
|
||||
# Test decode of simple Json Object
|
||||
# TODO this test makes `decodeString` tests fail
|
||||
# expect
|
||||
# input = Str.toUtf8 "{\"fruit\": \"apple\" }"
|
||||
|
||||
# actual = Decode.fromBytesPartial input fromUtf8
|
||||
# expected = Ok { fruit: "apple" }
|
||||
|
||||
# actual.result == expected
|
||||
|
||||
# Test decode of simple Json Object
|
||||
# TODO this test makes `decodeBool` tests fail
|
||||
# expect
|
||||
# input = Str.toUtf8 "{\"fruit\": true }"
|
||||
|
||||
# actual : DecodeResult { fruit : Bool }
|
||||
# actual = Decode.fromBytesPartial input fromUtf8
|
||||
# expected = Ok { fruit: Bool.true }
|
||||
|
||||
# actual.result == expected
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue