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)