csvlint 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +4 -0
- data/.github/workflows/push.yml +14 -2
- data/.pre-commit-hooks.yaml +5 -0
- data/.ruby-version +1 -1
- data/.standard_todo.yml +43 -0
- data/CHANGELOG.md +84 -32
- data/Dockerfile +16 -0
- data/Gemfile +2 -2
- data/README.md +30 -9
- data/Rakefile +7 -7
- data/csvlint.gemspec +14 -16
- data/docker_notes_for_windows.txt +20 -0
- data/features/step_definitions/cli_steps.rb +11 -11
- data/features/step_definitions/information_steps.rb +4 -4
- data/features/step_definitions/parse_csv_steps.rb +11 -11
- data/features/step_definitions/schema_validation_steps.rb +10 -10
- data/features/step_definitions/sources_steps.rb +1 -1
- data/features/step_definitions/validation_errors_steps.rb +19 -19
- data/features/step_definitions/validation_info_steps.rb +9 -9
- data/features/step_definitions/validation_warnings_steps.rb +11 -11
- data/features/support/aruba.rb +6 -6
- data/features/support/earl_formatter.rb +39 -39
- data/features/support/env.rb +10 -11
- data/features/support/load_tests.rb +107 -103
- data/features/support/webmock.rb +2 -2
- data/lib/csvlint/cli.rb +133 -130
- data/lib/csvlint/csvw/column.rb +279 -280
- data/lib/csvlint/csvw/date_format.rb +90 -92
- data/lib/csvlint/csvw/metadata_error.rb +1 -3
- data/lib/csvlint/csvw/number_format.rb +40 -32
- data/lib/csvlint/csvw/property_checker.rb +714 -717
- data/lib/csvlint/csvw/table.rb +49 -52
- data/lib/csvlint/csvw/table_group.rb +24 -23
- data/lib/csvlint/error_collector.rb +2 -0
- data/lib/csvlint/error_message.rb +0 -1
- data/lib/csvlint/field.rb +153 -141
- data/lib/csvlint/schema.rb +34 -42
- data/lib/csvlint/validate.rb +161 -143
- data/lib/csvlint/version.rb +1 -1
- data/lib/csvlint.rb +22 -23
- data/spec/csvw/column_spec.rb +15 -16
- data/spec/csvw/date_format_spec.rb +5 -7
- data/spec/csvw/number_format_spec.rb +2 -4
- data/spec/csvw/table_group_spec.rb +103 -105
- data/spec/csvw/table_spec.rb +71 -73
- data/spec/field_spec.rb +116 -121
- data/spec/schema_spec.rb +129 -139
- data/spec/spec_helper.rb +6 -6
- data/spec/validator_spec.rb +167 -190
- metadata +23 -55
data/spec/field_spec.rb
CHANGED
@@ -1,110 +1,108 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Csvlint::Field do
|
4
|
-
|
5
4
|
it "should validate required fields" do
|
6
|
-
field = Csvlint::Field.new("test", {
|
7
|
-
expect(
|
8
|
-
expect(
|
9
|
-
expect(
|
10
|
-
expect(
|
5
|
+
field = Csvlint::Field.new("test", {"required" => true})
|
6
|
+
expect(field.validate_column(nil)).to be(false)
|
7
|
+
expect(field.errors.first.category).to be(:schema)
|
8
|
+
expect(field.validate_column("")).to be(false)
|
9
|
+
expect(field.validate_column("data")).to be(true)
|
11
10
|
end
|
12
11
|
|
13
12
|
it "should include the failed constraints" do
|
14
|
-
field = Csvlint::Field.new("test", {
|
15
|
-
expect(
|
16
|
-
expect(
|
13
|
+
field = Csvlint::Field.new("test", {"required" => true})
|
14
|
+
expect(field.validate_column(nil)).to be(false)
|
15
|
+
expect(field.errors.first.constraints).to eql({"required" => true})
|
17
16
|
end
|
18
17
|
|
19
18
|
it "should validate minimum length" do
|
20
|
-
field = Csvlint::Field.new("test", {
|
21
|
-
expect(
|
22
|
-
expect(
|
23
|
-
expect(
|
24
|
-
expect(
|
25
|
-
expect(
|
19
|
+
field = Csvlint::Field.new("test", {"minLength" => 3})
|
20
|
+
expect(field.validate_column(nil)).to be(false)
|
21
|
+
expect(field.validate_column("")).to be(false)
|
22
|
+
expect(field.validate_column("ab")).to be(false)
|
23
|
+
expect(field.validate_column("abc")).to be(true)
|
24
|
+
expect(field.validate_column("abcd")).to be(true)
|
26
25
|
end
|
27
26
|
|
28
27
|
it "should validate maximum length" do
|
29
|
-
field = Csvlint::Field.new("test", {
|
30
|
-
expect(
|
31
|
-
expect(
|
32
|
-
expect(
|
33
|
-
expect(
|
34
|
-
expect(
|
28
|
+
field = Csvlint::Field.new("test", {"maxLength" => 3})
|
29
|
+
expect(field.validate_column(nil)).to be(true)
|
30
|
+
expect(field.validate_column("")).to be(true)
|
31
|
+
expect(field.validate_column("ab")).to be(true)
|
32
|
+
expect(field.validate_column("abc")).to be(true)
|
33
|
+
expect(field.validate_column("abcd")).to be(false)
|
35
34
|
end
|
36
35
|
|
37
36
|
it "should validate against regex" do
|
38
|
-
field = Csvlint::Field.new("test", {
|
39
|
-
expect(
|
40
|
-
expect(
|
37
|
+
field = Csvlint::Field.new("test", {"pattern" => "{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}"})
|
38
|
+
expect(field.validate_column("abc")).to be(false)
|
39
|
+
expect(field.validate_column("{3B0DA29C-C89A-4FAA-918A-0000074FA0E0}")).to be(true)
|
41
40
|
end
|
42
41
|
|
43
42
|
it "should apply combinations of constraints" do
|
44
|
-
field = Csvlint::Field.new("test", {
|
45
|
-
expect(
|
46
|
-
expect(
|
47
|
-
|
48
|
-
expect( field.validate_column( nil ) ).to be(false)
|
49
|
-
expect( field.errors.first.constraints ).to eql( { "required"=>true } )
|
43
|
+
field = Csvlint::Field.new("test", {"required" => true, "pattern" => "{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}"})
|
44
|
+
expect(field.validate_column("abc")).to be(false)
|
45
|
+
expect(field.errors.first.constraints).to eql({"pattern" => "{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}"})
|
50
46
|
|
51
|
-
expect(
|
47
|
+
expect(field.validate_column(nil)).to be(false)
|
48
|
+
expect(field.errors.first.constraints).to eql({"required" => true})
|
52
49
|
|
50
|
+
expect(field.validate_column("{3B0DA29C-C89A-4FAA-918A-0000074FA0E0}")).to be(true)
|
53
51
|
end
|
54
52
|
|
55
53
|
it "should enforce uniqueness for a column" do
|
56
|
-
field = Csvlint::Field.new("test", {
|
57
|
-
expect(
|
58
|
-
expect(
|
59
|
-
expect(
|
60
|
-
expect(
|
54
|
+
field = Csvlint::Field.new("test", {"unique" => true})
|
55
|
+
expect(field.validate_column("abc")).to be(true)
|
56
|
+
expect(field.validate_column("abc")).to be(false)
|
57
|
+
expect(field.errors.first.category).to be(:schema)
|
58
|
+
expect(field.errors.first.type).to be(:unique)
|
61
59
|
end
|
62
60
|
|
63
61
|
context "it should validate correct types" do
|
64
62
|
it "skips empty fields" do
|
65
|
-
field = Csvlint::Field.new("test", {
|
66
|
-
expect(
|
63
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#int"})
|
64
|
+
expect(field.validate_column("")).to be(true)
|
67
65
|
end
|
68
66
|
|
69
67
|
it "validates strings" do
|
70
|
-
field = Csvlint::Field.new("test", {
|
71
|
-
expect(
|
72
|
-
expect(
|
68
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#string"})
|
69
|
+
expect(field.validate_column("42")).to be(true)
|
70
|
+
expect(field.validate_column("forty-two")).to be(true)
|
73
71
|
end
|
74
72
|
|
75
73
|
it "validates ints" do
|
76
|
-
field = Csvlint::Field.new("test", {
|
77
|
-
expect(
|
78
|
-
expect(
|
74
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#int"})
|
75
|
+
expect(field.validate_column("42")).to be(true)
|
76
|
+
expect(field.validate_column("forty-two")).to be(false)
|
79
77
|
end
|
80
78
|
|
81
79
|
it "validates integers" do
|
82
|
-
field = Csvlint::Field.new("test", {
|
83
|
-
expect(
|
84
|
-
expect(
|
80
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#integer"})
|
81
|
+
expect(field.validate_column("42")).to be(true)
|
82
|
+
expect(field.validate_column("forty-two")).to be(false)
|
85
83
|
end
|
86
84
|
|
87
85
|
it "validates floats" do
|
88
|
-
field = Csvlint::Field.new("test", {
|
86
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#float"})
|
89
87
|
expect(field.validate_column("42.0")).to be(true)
|
90
88
|
expect(field.validate_column("42")).to be(true)
|
91
89
|
expect(field.validate_column("forty-two")).to be(false)
|
92
90
|
end
|
93
91
|
|
94
92
|
it "validates URIs" do
|
95
|
-
field = Csvlint::Field.new("test", {
|
93
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#anyURI"})
|
96
94
|
expect(field.validate_column("http://theodi.org/team")).to be(true)
|
97
95
|
expect(field.validate_column("https://theodi.org/team")).to be(true)
|
98
96
|
expect(field.validate_column("42.0")).to be(false)
|
99
97
|
end
|
100
98
|
|
101
99
|
it "works with invalid URIs" do
|
102
|
-
field = Csvlint::Field.new("test", {
|
100
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#anyURI"})
|
103
101
|
expect(field.validate_column("£123")).to be(false)
|
104
102
|
end
|
105
103
|
|
106
104
|
it "validates booleans" do
|
107
|
-
field = Csvlint::Field.new("test", {
|
105
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#boolean"})
|
108
106
|
expect(field.validate_column("true")).to be(true)
|
109
107
|
expect(field.validate_column("1")).to be(true)
|
110
108
|
expect(field.validate_column("false")).to be(true)
|
@@ -114,138 +112,135 @@ describe Csvlint::Field do
|
|
114
112
|
|
115
113
|
context "it should validate all kinds of integers" do
|
116
114
|
it "validates a non-positive integer" do
|
117
|
-
field = Csvlint::Field.new("test", {
|
115
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#nonPositiveInteger"})
|
118
116
|
expect(field.validate_column("0")).to be(true)
|
119
117
|
expect(field.validate_column("-1")).to be(true)
|
120
118
|
expect(field.validate_column("1")).to be(false)
|
121
119
|
end
|
122
120
|
|
123
121
|
it "validates a negative integer" do
|
124
|
-
field = Csvlint::Field.new("test", {
|
122
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#negativeInteger"})
|
125
123
|
expect(field.validate_column("0")).to be(false)
|
126
124
|
expect(field.validate_column("-1")).to be(true)
|
127
125
|
expect(field.validate_column("1")).to be(false)
|
128
126
|
end
|
129
127
|
|
130
128
|
it "validates a non-negative integer" do
|
131
|
-
field = Csvlint::Field.new("test", {
|
129
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#nonNegativeInteger"})
|
132
130
|
expect(field.validate_column("0")).to be(true)
|
133
131
|
expect(field.validate_column("-1")).to be(false)
|
134
132
|
expect(field.validate_column("1")).to be(true)
|
135
133
|
end
|
136
134
|
|
137
135
|
it "validates a positive integer" do
|
138
|
-
field = Csvlint::Field.new("test", {
|
136
|
+
field = Csvlint::Field.new("test", {"type" => "http://www.w3.org/2001/XMLSchema#positiveInteger"})
|
139
137
|
expect(field.validate_column("0")).to be(false)
|
140
138
|
expect(field.validate_column("-1")).to be(false)
|
141
|
-
expect(field.errors.first.constraints).to eql(
|
139
|
+
expect(field.errors.first.constraints).to eql({"type" => "http://www.w3.org/2001/XMLSchema#positiveInteger"})
|
142
140
|
expect(field.validate_column("1")).to be(true)
|
143
141
|
end
|
144
142
|
end
|
145
143
|
|
146
144
|
context "when validating ranges" do
|
147
|
-
|
148
145
|
it "should enforce minimum values" do
|
149
146
|
field = Csvlint::Field.new("test", {
|
150
|
-
|
151
|
-
|
147
|
+
"type" => "http://www.w3.org/2001/XMLSchema#int",
|
148
|
+
"minimum" => "40"
|
152
149
|
})
|
153
|
-
expect(
|
150
|
+
expect(field.validate_column("42")).to be(true)
|
154
151
|
|
155
152
|
field = Csvlint::Field.new("test", {
|
156
|
-
|
157
|
-
|
153
|
+
"type" => "http://www.w3.org/2001/XMLSchema#int",
|
154
|
+
"minimum" => "40"
|
158
155
|
})
|
159
|
-
expect(
|
160
|
-
expect(
|
156
|
+
expect(field.validate_column("39")).to be(false)
|
157
|
+
expect(field.errors.first.type).to eql(:below_minimum)
|
161
158
|
end
|
162
159
|
|
163
160
|
it "should enforce maximum values" do
|
164
161
|
field = Csvlint::Field.new("test", {
|
165
|
-
|
166
|
-
|
162
|
+
"type" => "http://www.w3.org/2001/XMLSchema#int",
|
163
|
+
"maximum" => "40"
|
167
164
|
})
|
168
|
-
expect(
|
165
|
+
expect(field.validate_column("39")).to be(true)
|
169
166
|
|
170
167
|
field = Csvlint::Field.new("test", {
|
171
|
-
|
172
|
-
|
168
|
+
"type" => "http://www.w3.org/2001/XMLSchema#int",
|
169
|
+
"maximum" => "40"
|
173
170
|
})
|
174
|
-
expect(
|
175
|
-
expect(
|
176
|
-
|
171
|
+
expect(field.validate_column("41")).to be(false)
|
172
|
+
expect(field.errors.first.type).to eql(:above_maximum)
|
177
173
|
end
|
178
174
|
end
|
179
175
|
|
180
176
|
context "when validating dates" do
|
181
177
|
it "should validate a date time" do
|
182
178
|
field = Csvlint::Field.new("test", {
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
expect(
|
179
|
+
"type" => "http://www.w3.org/2001/XMLSchema#dateTime"
|
180
|
+
})
|
181
|
+
expect(field.validate_column("2014-02-17T11:09:00Z")).to be(true)
|
182
|
+
expect(field.validate_column("invalid-date")).to be(false)
|
183
|
+
expect(field.validate_column("2014-02-17")).to be(false)
|
188
184
|
end
|
189
185
|
it "should validate a date" do
|
190
186
|
field = Csvlint::Field.new("test", {
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
expect(
|
187
|
+
"type" => "http://www.w3.org/2001/XMLSchema#date"
|
188
|
+
})
|
189
|
+
expect(field.validate_column("2014-02-17T11:09:00Z")).to be(false)
|
190
|
+
expect(field.validate_column("invalid-date")).to be(false)
|
191
|
+
expect(field.validate_column("2014-02-17")).to be(true)
|
196
192
|
end
|
197
193
|
it "should validate a time" do
|
198
194
|
field = Csvlint::Field.new("test", {
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
195
|
+
"type" => "http://www.w3.org/2001/XMLSchema#time"
|
196
|
+
})
|
197
|
+
expect(field.validate_column("11:09:00")).to be(true)
|
198
|
+
expect(field.validate_column("2014-02-17T11:09:00Z")).to be(false)
|
199
|
+
expect(field.validate_column("not-a-time")).to be(false)
|
200
|
+
expect(field.validate_column("27:97:00")).to be(false)
|
205
201
|
end
|
206
202
|
it "should validate a year" do
|
207
203
|
field = Csvlint::Field.new("test", {
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
204
|
+
"type" => "http://www.w3.org/2001/XMLSchema#gYear"
|
205
|
+
})
|
206
|
+
expect(field.validate_column("1999")).to be(true)
|
207
|
+
expect(field.validate_column("2525")).to be(true)
|
208
|
+
expect(field.validate_column("0001")).to be(true)
|
209
|
+
expect(field.validate_column("2014-02-17T11:09:00Z")).to be(false)
|
210
|
+
expect(field.validate_column("not-a-time")).to be(false)
|
211
|
+
expect(field.validate_column("27:97:00")).to be(false)
|
216
212
|
end
|
217
213
|
it "should validate a year-month" do
|
218
214
|
field = Csvlint::Field.new("test", {
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
215
|
+
"type" => "http://www.w3.org/2001/XMLSchema#gYearMonth"
|
216
|
+
})
|
217
|
+
expect(field.validate_column("1999-12")).to be(true)
|
218
|
+
expect(field.validate_column("2525-01")).to be(true)
|
219
|
+
expect(field.validate_column("2014-02-17T11:09:00Z")).to be(false)
|
220
|
+
expect(field.validate_column("not-a-time")).to be(false)
|
221
|
+
expect(field.validate_column("27:97:00")).to be(false)
|
226
222
|
end
|
227
223
|
it "should allow user to specify custom date time pattern" do
|
228
224
|
field = Csvlint::Field.new("test", {
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
expect(
|
235
|
-
expect(
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
225
|
+
"type" => "http://www.w3.org/2001/XMLSchema#dateTime",
|
226
|
+
"datePattern" => "%Y-%m-%d %H:%M:%S"
|
227
|
+
})
|
228
|
+
expect(field.validate_column("1999-12-01 10:00:00")).to be(true)
|
229
|
+
expect(field.validate_column("invalid-date")).to be(false)
|
230
|
+
expect(field.validate_column("2014-02-17")).to be(false)
|
231
|
+
expect(field.errors.first.constraints).to eql({
|
232
|
+
"type" => "http://www.w3.org/2001/XMLSchema#dateTime",
|
233
|
+
"datePattern" => "%Y-%m-%d %H:%M:%S"
|
234
|
+
})
|
240
235
|
end
|
241
236
|
it "should allow user to compare dates" do
|
242
237
|
field = Csvlint::Field.new("test", {
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
238
|
+
"type" => "http://www.w3.org/2001/XMLSchema#dateTime",
|
239
|
+
"datePattern" => "%Y-%m-%d %H:%M:%S",
|
240
|
+
"minimum" => "1990-01-01 10:00:00"
|
241
|
+
})
|
242
|
+
expect(field.validate_column("1999-12-01 10:00:00")).to be(true)
|
243
|
+
expect(field.validate_column("1989-12-01 10:00:00")).to be(false)
|
249
244
|
end
|
250
245
|
end
|
251
246
|
end
|