|
open System |
|
open Newtonsoft.Json.Linq |
|
|
|
module JsonTest = |
|
let tokenType2String tt = |
|
match tt with |
|
| JTokenType.None -> "None" |
|
| JTokenType.Object -> "Object" |
|
| JTokenType.Array -> "Array" |
|
| JTokenType.Constructor -> "Constructor" |
|
| JTokenType.Property -> "Property" |
|
| JTokenType.Comment -> "Comment" |
|
| JTokenType.Integer -> "Integer" |
|
| JTokenType.Float -> "Float" |
|
| JTokenType.String -> "String" |
|
| JTokenType.Boolean -> "Boolean" |
|
| JTokenType.Null -> "Null" |
|
| JTokenType.Undefined -> "Undefined" |
|
| JTokenType.Date -> "Date" |
|
| JTokenType.Raw -> "Raw" |
|
| JTokenType.Bytes -> "Bytes" |
|
| JTokenType.Guid -> "Guid" |
|
| JTokenType.Uri -> "Uri" |
|
| JTokenType.TimeSpan -> "TimeSpan" |
|
| _ -> failwith "Should never happen!" |
|
|
|
let toObject (t: JToken) = |
|
match t.Type with |
|
| JTokenType.Integer -> t.ToObject<int>() |> box |
|
| JTokenType.Float -> t.ToObject<float>() |> box |
|
| JTokenType.String -> t.ToObject<string>() |> box |
|
| JTokenType.Boolean -> t.ToObject<Boolean>() |> box |
|
| _ -> failwith "Should never happen!!!!" |
|
|
|
let getTypeName (target: JToken) = tokenType2String <| target.Type |
|
|
|
let hasSameValues (target: JToken) (source: JToken) = |
|
JToken.DeepEquals(target, source) |
|
|
|
let hasSameTypes (target: JToken) (source: JToken) = |
|
target.Type = source.Type |
|
|
|
let rec compareObjects (s:JObject) (t:JObject) initkey = |
|
|
|
let ss:seq<JProperty> = s |> Seq.cast |
|
let ss' = ss |> List.ofSeq |
|
let ts:seq<JProperty> = t |> Seq.cast |
|
let ts' = ts |> List.ofSeq |
|
|
|
let sks = ss' |> List.map (fun x -> x.Name) |
|
let tks = ts' |> List.map (fun x -> x.Name) |
|
let allkeys = sks @ tks |> List.distinctBy id |
|
|
|
let check key = |
|
let sv = s.GetValue(key) |
|
let tv = t.GetValue(key) |
|
if tv = null then |
|
[(sprintf "%s.%s not found in %s" initkey key "target")] |
|
elif sv = null then |
|
[(sprintf "%s.%s not found in %s" initkey key "source")] |
|
elif hasSameTypes sv tv |> not then |
|
[(sprintf "%s.%s.(source.type: %s) != %s.%s.(target.type: %s)" initkey key (getTypeName sv) initkey key (getTypeName tv))] |
|
elif sv.Type = JTokenType.Object then |
|
compareObjects |
|
(sv.ToObject<JObject>()) |
|
(tv.ToObject<JObject>()) |
|
(initkey + "." + key) |
|
elif sv.Type = JTokenType.Array then |
|
compareArrays |
|
(sv.ToObject<JArray>()) |
|
(tv.ToObject<JArray>()) |
|
(initkey + "." + key) |
|
elif hasSameValues sv tv |> not then |
|
[sprintf "%s.%s.(source.value: %A) != %s.%s.(target.value: %A)" initkey key (toObject sv) initkey key (toObject tv)] |
|
else |
|
[] |
|
|
|
allkeys |
|
|> List.map check |
|
|> List.concat |
|
|
|
and compareArrays(s: JArray) (t: JArray) initkey = |
|
|
|
let drillInto i = |
|
let si = s.Item(i) |
|
let ti = t.Item(i) |
|
|
|
if hasSameTypes si ti |> not then |
|
[(sprintf "%s[%i].(source.type: %s) != %s[%i].(target.type: %s)" initkey i (getTypeName si) initkey i (getTypeName ti))] |
|
elif si.Type = JTokenType.Object then |
|
compareObjects |
|
(si.ToObject<JObject>()) |
|
(ti.ToObject<JObject>()) |
|
(initkey + "[" + i.ToString() + "]") |
|
elif si.Type = JTokenType.Array then |
|
compareArrays |
|
(si.ToObject<JArray>()) |
|
(ti.ToObject<JArray>()) |
|
(initkey + "[" + i.ToString() + "]") |
|
elif hasSameValues si ti |> not then |
|
[sprintf "%s[%i].(source.value: %A) != %s[%i].(target.value: %A)" initkey i (toObject si) initkey i (toObject ti)] |
|
else |
|
[] |
|
|
|
if s.Count <> t.Count then |
|
[sprintf "%s.Count.(source: %A) != %s.Count.(target: %A)" initkey (s.Count) initkey (t.Count)] |
|
else |
|
seq {for i in 0 .. (s.Count - 1) do yield i} |
|
|> Seq.toList |
|
|> List.map drillInto |
|
|> List.concat |
|
|
|
|
|
open JsonTest |
|
[<EntryPoint>] |
|
let main argv = |
|
|
|
let o1 = JObject.Parse( |
|
"""{ |
|
'CPU': 'Intel', |
|
'Drives': { |
|
'DVD': false, |
|
'Gigabytes': 500 |
|
}, |
|
'Ram': 400 |
|
}""") |
|
let o2 = JObject.Parse( |
|
"""{ |
|
'CPU': 'Intel', |
|
'Ram': "400", |
|
'Drives': { |
|
'DVD': true, |
|
'Gigabytes1': 501 |
|
} |
|
}""") |
|
|
|
let o3 = JObject.Parse( |
|
"""{ |
|
'CPU': 'Intel', |
|
'Drives': { |
|
'DVD': true, |
|
'Gigabytes': 500 |
|
}, |
|
'Ram': 400, |
|
'Ports' : [ |
|
1, |
|
2 |
|
] |
|
}""") |
|
let o4 = JObject.Parse( |
|
"""{ |
|
'CPU': 'Intel', |
|
'Ram': 400, |
|
'Drives': { |
|
'DVD': true, |
|
'Gigabytes': 500 |
|
}, |
|
'Ports' : [ |
|
1, |
|
2, |
|
3 |
|
] |
|
}""") |
|
|
|
let o5 = JObject.Parse( |
|
"""{ |
|
'CPU': 'Intel', |
|
'Drives': { |
|
'DVD': true, |
|
'Gigabytes': 500 |
|
}, |
|
'Ram': 400, |
|
'Ports' : [ |
|
1, |
|
2, |
|
{'foo': [1, 2]} |
|
] |
|
}""") |
|
let o6 = JObject.Parse( |
|
"""{ |
|
'CPU': 'Intel', |
|
'Ram': 400, |
|
'Drives': { |
|
'DVD': true, |
|
'Gigabytes': 500 |
|
}, |
|
'Ports' : [ |
|
1, |
|
2, |
|
{'foo': [1, 'bar']} |
|
] |
|
}""") |
|
printfn "RESULT: %A" (compareObjects o1 o2 "#") |
|
printfn "RESULT: %A" (compareObjects o3 o4 "#") |
|
printfn "RESULT: %A" (compareObjects o5 o6 "#") |
|
|
|
0 |