[
{
"name": "ascending by a string key",
"args": [[{ "n": "pear" }, { "n": "apple" }, { "n": "fig" }], "n", "asc"],
"expect": [{ "n": "apple" }, { "n": "fig" }, { "n": "pear" }]
},
{
"name": "descending by a string key",
"args": [[{ "n": "pear" }, { "n": "apple" }, { "n": "fig" }], "n", "desc"],
"expect": [{ "n": "pear" }, { "n": "fig" }, { "n": "apple" }]
},
{
"name": "ascending by a number key",
"args": [[{ "s": 30 }, { "s": 4 }, { "s": 100 }], "s", "asc"],
"expect": [{ "s": 4 }, { "s": 30 }, { "s": 100 }]
},
{
"name": "descending by a number key",
"args": [[{ "s": 30 }, { "s": 4 }, { "s": 100 }], "s", "desc"],
"expect": [{ "s": 100 }, { "s": 30 }, { "s": 4 }]
},
{
"name": "ties keep their input order ascending",
"args": [[{ "n": "a", "s": 5 }, { "n": "b", "s": 1 }, { "n": "c", "s": 5 }, { "n": "d", "s": 1 }], "s", "asc"],
"expect": [{ "n": "b", "s": 1 }, { "n": "d", "s": 1 }, { "n": "a", "s": 5 }, { "n": "c", "s": 5 }]
},
{
"name": "ties keep their input order descending too: the tied block is not flipped",
"args": [[{ "n": "a", "s": 5 }, { "n": "b", "s": 1 }, { "n": "c", "s": 5 }, { "n": "d", "s": 1 }], "s", "desc"],
"expect": [{ "n": "a", "s": 5 }, { "n": "c", "s": 5 }, { "n": "b", "s": 1 }, { "n": "d", "s": 1 }]
},
{
"name": "nulls and missing keys sort last ascending, keeping their own order",
"args": [[{ "n": "a", "s": null }, { "n": "b", "s": 2 }, { "n": "c" }, { "n": "d", "s": 1 }], "s", "asc"],
"expect": [{ "n": "d", "s": 1 }, { "n": "b", "s": 2 }, { "n": "a", "s": null }, { "n": "c" }]
},
{
"name": "nulls stay last descending: the rows we know nothing about never come first",
"args": [[{ "n": "a", "s": null }, { "n": "b", "s": 2 }, { "n": "c" }, { "n": "d", "s": 1 }], "s", "desc"],
"expect": [{ "n": "b", "s": 2 }, { "n": "d", "s": 1 }, { "n": "a", "s": null }, { "n": "c" }]
},
{
"name": "a list of nothing but absent values comes back in input order",
"args": [[{ "n": "a" }, { "n": "b", "s": null }, { "n": "c" }], "s", "asc"],
"expect": [{ "n": "a" }, { "n": "b", "s": null }, { "n": "c" }]
},
{
"name": "an empty list sorts to an empty list",
"args": [[], "s", "asc"],
"expect": []
},
{
"name": "a single record is already sorted, in either direction",
"args": [[{ "n": "only", "s": 7 }], "s", "desc"],
"expect": [{ "n": "only", "s": 7 }]
},
{
"name": "mixed types have one total order ascending: booleans, then numbers, then strings",
"args": [[{ "v": "zebra" }, { "v": 10 }, { "v": true }, { "v": false }, { "v": "apple" }, { "v": 2 }], "v", "asc"],
"expect": [{ "v": false }, { "v": true }, { "v": 2 }, { "v": 10 }, { "v": "apple" }, { "v": "zebra" }]
},
{
"name": "mixed types reverse cleanly descending",
"args": [[{ "v": "zebra" }, { "v": 10 }, { "v": true }, { "v": false }, { "v": "apple" }, { "v": 2 }], "v", "desc"],
"expect": [{ "v": "zebra" }, { "v": "apple" }, { "v": 10 }, { "v": 2 }, { "v": true }, { "v": false }]
},
{
"name": "integers and fractions interleave by value, not by type",
"args": [[{ "v": 3 }, { "v": 1.5 }, { "v": 2 }, { "v": 0.5 }], "v", "asc"],
"expect": [{ "v": 0.5 }, { "v": 1.5 }, { "v": 2 }, { "v": 3 }]
},
{
"name": "strings compare by code point, so capitals sort before lowercase",
"args": [[{ "v": "apple" }, { "v": "Banana" }, { "v": "Apple" }, { "v": "banana" }], "v", "asc"],
"expect": [{ "v": "Apple" }, { "v": "Banana" }, { "v": "apple" }, { "v": "banana" }]
},
{
"name": "a prefix sorts before the longer string, and accented letters sort after ASCII",
"args": [[{ "v": "Zoë" }, { "v": "Zoe" }, { "v": "Zo" }, { "v": "" }], "v", "asc"],
"expect": [{ "v": "" }, { "v": "Zo" }, { "v": "Zoe" }, { "v": "Zoë" }]
},
{
"name": "records with different shapes sort on the one field they share",
"args": [[{ "kind": "credit", "n": 2 }, { "kind": "invoice", "n": 1, "lines": [1, 2] }, { "kind": "quote", "n": 3, "meta": { "draft": true } }], "n", "asc"],
"expect": [{ "kind": "invoice", "n": 1, "lines": [1, 2] }, { "kind": "credit", "n": 2 }, { "kind": "quote", "n": 3, "meta": { "draft": true } }]
},
{
"name": "an unknown direction is an error, not a silent ascending sort",
"args": [[{ "s": 1 }], "s", "ascending"],
"expectError": "direction must be \"asc\" or \"desc\""
},
{
"name": "a list at the sort key has no defensible order",
"args": [[{ "s": 1 }, { "s": [1, 2] }], "s", "asc"],
"expectError": "list or map"
},
{
"name": "a map at the sort key has no defensible order",
"args": [[{ "s": 1 }, { "s": { "a": 1 } }], "s", "asc"],
"expectError": "list or map"
},
{
"name": "an empty key name is a caller bug",
"args": [[{ "s": 1 }], "", "asc"],
"expectError": "non-empty key name"
}
]