Repository navigation
Expand file tree
/
Copy pathduration_compliance_test.go
More file actions
114 lines (98 loc) · 3.38 KB
/
Copy pathduration_compliance_test.go
File metadata and controls
114 lines (98 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package strfmt
import (
"encoding/json"
"iter"
"os"
"slices"
"testing"
"github.com/go-openapi/testify/v2/assert"
"github.com/go-openapi/testify/v2/require"
)
// TestDurationISO8601_Compliance asserts the strict parser matches the official
// JSON Schema Test Suite for the "duration" format (RFC 3339 Appendix A).
func TestDurationISO8601_Compliance(t *testing.T) {
for tc := range durationTestCases(t) {
t.Run(tc.Desc, func(t *testing.T) {
got := IsDurationISO8601(tc.Input)
assert.Equalf(t, tc.Valid, got,
"input %q: strict validity mismatch (%s)", tc.Input, tc.Desc)
})
}
}
// TestDurationISO8601_Lenient checks that DurationLenient accepts exactly the
// cases the strict grammar rejects for leniency reasons.
func TestDurationISO8601_Lenient(t *testing.T) {
lenient := DurationLenient{}.isoDurationConfig()
for tc := range lenientISO8601DurationCases() {
if tc.Valid {
t.Run("lenient/"+tc.Desc, func(t *testing.T) {
assert.Falsef(t, IsDurationISO8601(tc.Input), "strict should reject %q", tc.Input)
_, err := parseISO8601Duration(tc.Input, lenient)
assert.NoErrorf(t, err, "lenient should accept %q", tc.Input)
})
continue
}
// Ordering is still enforced under leniency.
t.Run("lenient-rejects/"+tc.Desc, func(t *testing.T) {
_, err := parseISO8601Duration(tc.Input, lenient)
assert.Errorf(t, err, "lenient should still reject out-of-order %q", tc.Input)
})
}
}
// jsonSchemaSuiteGroup mirrors the JSON Schema Test Suite file layout.
type jsonSchemaSuiteGroup struct {
Description string `json:"description"`
Tests []struct {
Description string `json:"description"`
Data json.RawMessage `json:"data"`
Valid bool `json:"valid"`
} `json:"tests"`
}
type durationTestCase struct {
Desc string
Input string
Valid bool
}
func durationTestCases(t *testing.T) iter.Seq[durationTestCase] {
t.Helper()
return func(yield func(durationTestCase) bool) {
raw, err := os.ReadFile("testdata/jsonschema-suite/duration.json")
require.NoError(t, err)
var groups []jsonSchemaSuiteGroup
require.NoError(t, json.Unmarshal(raw, &groups))
for _, g := range groups {
for _, tc := range g.Tests {
// The parser only ever sees string data; the format keyword ignores
// non-string JSON values. Skip explicit JSON null (decodes to "").
if string(tc.Data) == "null" {
continue
}
var s string
if json.Unmarshal(tc.Data, &s) != nil {
continue
}
tc := durationTestCase{tc.Description, s, tc.Valid}
if !yield(tc) {
return
}
}
}
}
}
func lenientISO8601DurationCases() iter.Seq[durationTestCase] {
return slices.Values([]durationTestCase{
{Input: "PT0.5S", Desc: "fraction", Valid: true},
{Input: "P1,5D", Desc: "comma fraction", Valid: true},
{Input: "-P1D", Desc: "sign", Valid: true},
{Input: "+P1D", Desc: "sign", Valid: true},
{Input: " P1D", Desc: "whitespace", Valid: true},
{Input: "P1D ", Desc: "whitespace", Valid: true},
{Input: "P1Y2D", Desc: "relaxed anchoring (gap)", Valid: true},
{Input: "PT1H2S", Desc: "relaxed anchoring (gap)", Valid: true},
{Input: "P1Y2W", Desc: "week combinable", Valid: true},
{Input: "P2D1Y", Desc: "invalid under lenient", Valid: false},
{Input: "PT1M2H", Desc: "invalid under lenient (2)", Valid: false},
})
}