spec/metadata_spec.rb in rdf-tabular-0.1.3.1 vs spec/metadata_spec.rb in rdf-tabular-0.2.0
- old
+ new
@@ -12,11 +12,11 @@
when /\.csv/ then 'text/csv'
else 'text/plain'
end
case file
- when "metadata.json", "country-codes-and-names.csv-metadata.json"
+ when "csv-metadata.json", "country-codes-and-names.csv-metadata.json"
{status: 401}
else
{
body: File.read(File.expand_path("../data/#{file}", __FILE__)),
status: 200,
@@ -35,11 +35,19 @@
},
datatype: {
valid: (%w(anyAtomicType string token language Name NCName boolean gYear number binary datetime any xml html json) +
[{"base" => "string"}]
),
- invalid: [1, true, "foo", "anyType", "anySimpleType", "IDREFS"]
+ invalid: [1, true, "http://example.org/",
+ {"base" => "foo"},
+ {"base" => "anyType"},
+ {"base" => "anySimpleType"},
+ {"base" => "IDREFS"},
+ ],
+ errors: [{"@id" => "_:foo"},
+ {"@id" => "http://www.w3.org/2001/XMLSchema#string"},
+ ]
},
default: {
valid: ["foo"],
invalid: [1, %w(foo bar), true, nil]
},
@@ -66,12 +74,12 @@
required: {
valid: [true, false],
invalid: [nil, "foo", 1, 0, "true", "false", "TrUe", "fAlSe", "1", "0"],
},
separator: {
- valid: %w(, a | :) + [nil],
- invalid: [1, false] + %w(foo ::)
+ valid: %w(, a | : foo ::) + [nil],
+ invalid: [1, false]
},
"textDirection" => {
valid: %w(rtl ltr),
invalid: %w(foo default)
},
@@ -85,23 +93,29 @@
},
}.each do |prop, params|
context prop.to_s do
if allowed
it "validates" do
- params[:valid].each do |v|
+ params.fetch(:valid, {}).each do |v|
subject.send("#{prop}=".to_sym, v)
expect(subject.errors).to be_empty
expect(subject.warnings).to be_empty
end
end
it "invalidates" do
- params[:invalid].each do |v|
+ params.fetch(:invalid, {}).each do |v|
subject.send("#{prop}=".to_sym, v)
expect(subject.errors).to be_empty
expect(subject.warnings).not_to be_empty
end
end
+ it "errors" do
+ params.fetch(:error, {}).each do |v|
+ subject.send("#{prop}=".to_sym, v)
+ expect(subject.errors).not_to be_empty
+ end
+ end
else
it "does not allow" do
params[:valid].each do |v|
subject.send("#{prop}=".to_sym, v)
expect(subject.errors).to be_empty
@@ -586,16 +600,16 @@
notes: {
valid: [{}, [{}]],
invalid: [1, true, nil]
},
tableDirection: {
- valid: %w(rtl ltr default),
+ valid: %w(rtl ltr auto),
warning: %w(foo true 1)
},
transformations: {
- valid: [[RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")]],
- warning: [RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")] +
+ valid: [[RDF::Tabular::Transformation.new({url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/"}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"))]],
+ warning: [RDF::Tabular::Transformation.new({url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/"}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"))] +
%w(foo true 1)
},
dialect: {
valid: [{skipRows: 1}],
warning: [1]
@@ -641,20 +655,20 @@
tableSchema: {
valid: [RDF::Tabular::Schema.new({})],
warning: [1, true, nil]
},
tableDirection: {
- valid: %w(rtl ltr default),
+ valid: %w(rtl ltr auto),
warning: %w(foo true 1)
},
dialect: {
valid: [{skipRows: 1}],
warning: [1]
},
transformations: {
- valid: [[RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")]],
- warning: [RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")] +
+ valid: [[RDF::Tabular::Transformation.new({url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/"}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"))]],
+ warning: [RDF::Tabular::Transformation.new({url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/"}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"))] +
%w(foo true 1)
},
notes: {
valid: [{}, [{}]],
invalid: [1, true, nil]
@@ -1012,10 +1026,11 @@
context "datatypes" do
{
# Strings
"string with no constraints" => {base: "string", value: "foo", result: "foo"},
"string with matching length" => {base: "string", value: "foo", length: 3, result: "foo"},
+ "string matching null when required" => {base: "string", value: "NULL", null: "NULL", required: true},
"string with wrong length" => {
base: "string",
value: "foo",
length: 4,
errors: ["foo does not have length 4"]
@@ -1038,40 +1053,35 @@
base: "decimal",
value: "4"
},
"decimal with matching pattern" => {
base: "decimal",
- format: {pattern: '\d{3}'},
+ format: {"pattern" => '000'},
value: "123"
},
"decimal with wrong pattern" => {
base: "decimal",
- format: {pattern: '\d{4}'},
+ format: {"pattern" => '0000'},
value: "123",
errors: [/123 does not match pattern/]
},
- "decimal with implicit groupChar" => {
- base: "decimal",
- value: %("123,456.789"),
- result: "123456.789"
- },
"decimal with explicit groupChar" => {
base: "decimal",
- format: {groupChar: ";"},
+ format: {"groupChar" => ";"},
value: "123;456.789",
result: "123456.789"
},
"decimal with repeated groupChar" => {
base: "decimal",
- format: {groupChar: ";"},
+ format: {"groupChar" => ";"},
value: "123;;456.789",
result: "123;;456.789",
errors: [/has repeating/]
},
"decimal with explicit decimalChar" => {
base: "decimal",
- format: {decimalChar: ";"},
+ format: {"decimalChar" => ";"},
value: "123456;789",
result: "123456.789"
},
"invalid decimal" => {
base: "decimal",
@@ -1079,15 +1089,17 @@
result: "123456.789e10",
errors: ["123456.789e10 is not a valid decimal"]
},
"decimal with percent" => {
base: "decimal",
+ format: {"groupChar" => ","},
value: "123456.789%",
result: "1234.56789"
},
"decimal with per-mille" => {
base: "decimal",
+ format: {"groupChar" => ","},
value: "123456.789‰",
result: "123.456789"
},
"valid integer" => {base: "integer", value: "1234"},
"invalid integer" => {base: "integer", value: "1234.56", errors: ["1234.56 is not a valid integer"]},
@@ -1119,11 +1131,11 @@
"valid number" => {base: "number", value: "1234.456E789"},
"invalid number" => {base: "number", value: "1z", errors: ["1z is not a valid number"]},
"NaN number" => {base: "number", value: "NaN"},
"INF number" => {base: "number", value: "INF"},
"-INF number" => {base: "number", value: "-INF"},
- "valid float" => {base: "float", value: "1234.456E789"},
+ "valid float" => {base: "float", value: "1234.456E7"},
"invalid float" => {base: "float", value: "1z", errors: ["1z is not a valid float"]},
"NaN float" => {base: "float", value: "NaN"},
"INF float" => {base: "float", value: "INF"},
"-INF float" => {base: "float", value: "-INF"},
@@ -1150,17 +1162,19 @@
"validate date d.M.yyyy" => {base: "date", value: "22.3.2015", format: "d.M.yyyy", result: "2015-03-22"},
"validate date MM.dd.yyyy" => {base: "date", value: "03.22.2015", format: "MM.dd.yyyy", result: "2015-03-22"},
"validate date M.d.yyyy" => {base: "date", value: "3.22.2015", format: "M.d.yyyy", result: "2015-03-22"},
# Times
+ "valid time HH:mm:ss.S" => {base: "time", value: "15:02:37.1", format: "HH:mm:ss.S", result: "15:02:37.1"},
"valid time HH:mm:ss" => {base: "time", value: "15:02:37", format: "HH:mm:ss", result: "15:02:37"},
"valid time HHmmss" => {base: "time", value: "150237", format: "HHmmss", result: "15:02:37"},
"valid time HH:mm" => {base: "time", value: "15:02", format: "HH:mm", result: "15:02:00"},
"valid time HHmm" => {base: "time", value: "1502", format: "HHmm", result: "15:02:00"},
# DateTimes
"valid dateTime yyyy-MM-ddTHH:mm:ss" => {base: "dateTime", value: "2015-03-15T15:02:37", format: "yyyy-MM-ddTHH:mm:ss", result: "2015-03-15T15:02:37"},
+ "valid dateTime yyyy-MM-ddTHH:mm:ss.S" => {base: "dateTime", value: "2015-03-15T15:02:37.1", format: "yyyy-MM-ddTHH:mm:ss.S", result: "2015-03-15T15:02:37.1"},
"valid dateTime yyyy-MM-dd HH:mm:ss" => {base: "dateTime", value: "2015-03-15 15:02:37", format: "yyyy-MM-dd HH:mm:ss", result: "2015-03-15T15:02:37"},
"valid dateTime yyyyMMdd HHmmss" => {base: "dateTime", value: "20150315 150237", format: "yyyyMMdd HHmmss", result: "2015-03-15T15:02:37"},
"valid dateTime dd-MM-yyyy HH:mm" => {base: "dateTime", value: "15-03-2015 15:02", format: "dd-MM-yyyy HH:mm", result: "2015-03-15T15:02:00"},
"valid dateTime d-M-yyyy HHmm" => {base: "dateTime", value: "15-3-2015 1502", format: "d-M-yyyy HHmm", result: "2015-03-15T15:02:00"},
"valid dateTime yyyy-MM-ddTHH:mm" => {base: "dateTime", value: "2015-03-15T15:02", format: "yyyy-MM-ddTHH:mm", result: "2015-03-15T15:02:00"},
@@ -1208,21 +1222,10 @@
"valid token" => {base: "token", value: "some thing", result: RDF::Literal("some thing", datatype: RDF::XSD.token)},
"valid language" => {base: "language", value: "en", result: RDF::Literal("en", datatype: RDF::XSD.language)},
"valid Name" => {base: "Name", value: "someThing", result: RDF::Literal("someThing", datatype: RDF::XSD.Name)},
"valid NMTOKEN" => {base: "NMTOKEN", value: "someThing", result: RDF::Literal("someThing", datatype: RDF::XSD.NMTOKEN)},
- # Unsupported datatypes
- "anyType not allowed" => {base: "anyType", value: "some thing", errors: [/unsupported datatype/]},
- "anySimpleType not allowed" => {base: "anySimpleType", value: "some thing", errors: [/unsupported datatype/]},
- "ENTITIES not allowed" => {base: "ENTITIES", value: "some thing", errors: [/unsupported datatype/]},
- "IDREFS not allowed" => {base: "IDREFS", value: "some thing", errors: [/unsupported datatype/]},
- "NMTOKENS not allowed" => {base: "NMTOKENS", value: "some thing", errors: [/unsupported datatype/]},
- "ENTITY not allowed" => {base: "ENTITY", value: "something", errors: [/unsupported datatype/]},
- "ID not allowed" => {base: "ID", value: "something", errors: [/unsupported datatype/]},
- "IDREF not allowed" => {base: "IDREF", value: "something", errors: [/unsupported datatype/]},
- "NOTATION not allowed" => {base: "NOTATION", value: "some:thing", errors: [/unsupported datatype/]},
-
# Aliases
"number is alias for double" => {base: "number", value: "1234.456E789", result: RDF::Literal("1234.456E789", datatype: RDF::XSD.double)},
"binary is alias for base64Binary" => {base: "binary", value: "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g", result: RDF::Literal("Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g", datatype: RDF::XSD.base64Binary)},
"datetime is alias for dateTime" => {base: "dateTime", value: "15-3-2015 1502", format: "d-M-yyyy HHmm", result: RDF::Literal("2015-03-15T15:02:00", datatype: RDF::XSD.dateTime)},
"any is alias for anyAtomicType" => {base: "any", value: "some thing", result: RDF::Literal("some thing", datatype: RDF::XSD.anyAtomicType)},
@@ -1268,13 +1271,79 @@
end
specify {expect(subject.value).to eql result}
end
end
+
+ context "Unsupported datatypes" do
+ %w(anyType anySimpleType ENTITIES IDREFS NMTOKENS ENTITY ID IDREF NOTATAION foo).each do |base|
+ it "detects #{base} as unsupported" do
+ md = RDF::Tabular::Table.new({
+ url: "http://example.com/table.csv",
+ tableSchema: {
+ columns: [{
+ name: "name",
+ datatype: base
+ }]
+ }
+ })
+ expect(md.warnings).not_to be_empty
+ end
+ end
+ end
end
end
+ describe "#build_number_re" do
+ subject {RDF::Tabular::Datatype.new({})}
+ {
+ '#,##0.##' => /^\d{1,}\.\d{,2}$/,
+ '#,##0.###' => /^\d{1,}\.\d{,3}$/,
+ '###0.#####' => /^\d{1,}\.\d{,5}$/,
+ '###0.0000#' => /^\d{1,}\.\d{4,5}$/,
+ '00000.0000' => /^\d{5}\.\d{4}$/,
+
+ '0' => /^\d{1}$/,
+ '00' => /^\d{2}$/,
+ '#' => /^\d*$/,
+ '##' => /^\d*$/,
+
+ '.0' => /^\.\d{1}$/,
+ '.00' => /^\.\d{2}$/,
+ '.#' => /^\.\d{,1}$/,
+ '.##' => /^\.\d{,2}$/,
+
+ '+0' => /^+\d{1}$/,
+ '-0' => /^-\d{1}$/,
+ '%0' => /^%\d{1}$/,
+ '‰0' => /^‰\d{1}$/,
+ '0%' => /^\d{1}%$/,
+ '0‰' => /^\d{1}‰$/,
+ '0.0%' => /^\d{1}\.\d{1}%$/,
+
+ '#0.0#E#0' => /^\d{1,}\.\d{1,2}E\d{1,2}$/,
+ '#0.0#E+#' => /^\d{1,}\.\d{1,2}E+\d{,1}$/,
+ '#0.0#E-00' => /^\d{1,}\.\d{1,2}E-\d{2}$/,
+ '#0.0#E#0%' => /^\d{1,}\.\d{1,2}E\d{1,2}%$/,
+ }.each do |pattern,regexp|
+ it "generates #{regexp} for #{pattern}" do
+ expect(subject.build_number_re(pattern, ",", ".")).to eql regexp
+ end
+ end
+
+ %W{
+ +%0
+ 0#
+ 0E0
+ 0-
+ }.each do |pattern|
+ it "recognizes bad pattern #{pattern}" do
+ expect{subject.build_number_re(pattern, ",", ".")}.to raise_error(ArgumentError)
+ end
+ end
+ end
+
describe "#common_properties" do
describe "#normalize!" do
{
"string with no language" => [
%({
@@ -1509,14 +1578,29 @@
"@context": "http://www.w3.org/ns/csvw",
"@type": "Table",
"url": "http://example.org/table1",
"tableSchema": {"columns": [{"titles": "foo"}]}
}),
- R: true
+ R: false
},
+ "tables with mismatch columns on name/titles" => {
+ A: %({
+ "@context": "http://www.w3.org/ns/csvw",
+ "@type": "Table",
+ "url": "http://example.org/table1",
+ "tableSchema": {"columns": [{"name": "foo"}]}
+ }),
+ B: %({
+ "@context": "http://www.w3.org/ns/csvw",
+ "@type": "Table",
+ "url": "http://example.org/table1",
+ "tableSchema": {"columns": [{"titles": "bar"}]}
+ }),
+ R: false
+ },
}.each do |name, props|
it name do
- a = described_class.new(::JSON.parse(props[:A]))
+ a = described_class.new(::JSON.parse(props[:A]), validate: true)
b = described_class.new(::JSON.parse(props[:B]))
if props[:R]
expect {a.verify_compatible!(b)}.not_to raise_error
else
expect {a.verify_compatible!(b)}.to raise_error(RDF::Tabular::Error)