gonum.org/v1/gonum@v0.14.0/graph/formats/rdf/rdf_test.go (about) 1 // Copyright ©2020 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rdf 6 7 import ( 8 "archive/tar" 9 "compress/gzip" 10 "fmt" 11 "io" 12 "os" 13 "path/filepath" 14 "reflect" 15 "strings" 16 "testing" 17 ) 18 19 func TestRDFWorkingGroupSuite(t *testing.T) { 20 for _, file := range []string{ 21 "ntriple_tests.tar.gz", 22 "nquad_tests.tar.gz", 23 } { 24 suite, err := os.Open(filepath.Join("testdata", file)) 25 if err != nil { 26 t.Fatalf("Failed to open test suite in %q: %v", file, err) 27 } 28 defer suite.Close() 29 30 r, err := gzip.NewReader(suite) 31 if err != nil { 32 t.Fatalf("Failed to uncompress test suite in %q: %v", file, err) 33 } 34 35 tr := tar.NewReader(r) 36 for { 37 h, err := tr.Next() 38 if err != nil { 39 if err == io.EOF { 40 break 41 } 42 t.Fatalf("Unexpected error while reading suite archive: %v", err) 43 } 44 45 h.Name = filepath.Base(h.Name) 46 if filepath.Ext(h.Name) != ".nt" && filepath.Ext(h.Name) != ".nq" { 47 continue 48 } 49 if _, ok := testSuite[h.Name]; !ok { 50 t.Errorf("Missing test suite item %q", h.Name) 51 continue 52 } 53 54 isBad := strings.Contains(h.Name, "bad") 55 56 var got []statement 57 dec := NewDecoder(tr) 58 for i := 0; ; i++ { 59 s, err := dec.Unmarshal() 60 if err == io.EOF { 61 break 62 } 63 gotBad := err != nil 64 if gotBad != isBad { 65 t.Errorf("Unexpected error return for test suite item %q, got: %v", h.Name, err) 66 } 67 68 var subj, pred, obj, lab term 69 if s != nil { 70 subj.text, subj.qual, subj.kind, _ = s.Subject.Parts() 71 pred.text, pred.qual, pred.kind, _ = s.Predicate.Parts() 72 obj.text, obj.qual, obj.kind, _ = s.Object.Parts() 73 lab.text, lab.qual, lab.kind, _ = s.Label.Parts() 74 if lab.text == "" { 75 lab = term{} 76 } 77 got = append(got, statement{testSuite[h.Name][i].input, subj, pred, obj, lab}) 78 } 79 80 if !gotBad { 81 _, err = ParseNQuad(s.String()) 82 if err != nil { 83 t.Errorf("Unexpected error return for valid statement in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) 84 } 85 86 st, err := termFor(subj.text, subj.qual, subj.kind) 87 if err != nil { 88 t.Errorf("Unexpected error return for valid subject in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) 89 } 90 pt, err := termFor(pred.text, pred.qual, pred.kind) 91 if err != nil { 92 t.Errorf("Unexpected error return for valid predicate in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) 93 } 94 ot, err := termFor(obj.text, obj.qual, obj.kind) 95 if err != nil { 96 t.Errorf("Unexpected error return for valid object in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) 97 } 98 lt, err := termFor(lab.text, lab.qual, lab.kind) 99 if err != nil { 100 t.Errorf("Unexpected error return for valid label in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) 101 } 102 103 // We can't check that we recreate the original from the test suite 104 // due to escaping, but we can check for a second pass through the 105 // round-trip. 106 c := &Statement{Subject: st, Predicate: pt, Object: ot, Label: lt} 107 pc, err := ParseNQuad(c.String()) 108 if err != nil { 109 t.Errorf("Unexpected error return for reconstructed statement in test suite item %q (%#v) got: %v rendered as\n%[2]s", h.Name, s, err) 110 } 111 if !reflect.DeepEqual(c, pc) { 112 t.Errorf("Unexpected reconstruction:\norig: %#v\ncons: %#v\nparsed:%#v", s, c, pc) 113 } 114 } 115 } 116 117 if !reflect.DeepEqual(testSuite[h.Name], got) { 118 t.Errorf("Unexpected result for test suite item %q", h.Name) 119 } 120 } 121 } 122 } 123 124 func termFor(text, qual string, kind Kind) (Term, error) { 125 switch kind { 126 case Invalid: 127 return Term{}, nil 128 case Blank: 129 return NewBlankTerm(text) 130 case IRI: 131 return NewIRITerm(text) 132 case Literal: 133 return NewLiteralTerm(text, qual) 134 default: 135 panic(fmt.Sprintf("bad test kind=%d", kind)) 136 } 137 } 138 139 var escapeSequenceTests = []struct { 140 escaped string 141 unEscaped string 142 canRoundTrip bool 143 }{ 144 {escaped: `plain text!`, unEscaped: "plain text!", canRoundTrip: true}, 145 {escaped: `\t`, unEscaped: "\t", canRoundTrip: false}, 146 {escaped: `\b`, unEscaped: "\b", canRoundTrip: false}, 147 {escaped: `\n`, unEscaped: "\n", canRoundTrip: true}, 148 {escaped: `\r`, unEscaped: "\r", canRoundTrip: true}, 149 {escaped: `\f`, unEscaped: "\f", canRoundTrip: false}, 150 {escaped: `\\`, unEscaped: "\\", canRoundTrip: true}, 151 {escaped: `\u0080`, unEscaped: "\u0080", canRoundTrip: true}, 152 {escaped: `\U00000080`, unEscaped: "\u0080", canRoundTrip: false}, 153 {escaped: `\t\b\n\r\f\"'\\`, unEscaped: "\t\b\n\r\f\"'\\", canRoundTrip: false}, 154 155 {escaped: `\t\u0080`, unEscaped: "\t\u0080", canRoundTrip: false}, 156 {escaped: `\b\U00000080`, unEscaped: "\b\u0080", canRoundTrip: false}, 157 {escaped: `\u0080\n`, unEscaped: "\u0080\n", canRoundTrip: true}, 158 {escaped: `\U00000080\r`, unEscaped: "\u0080\r", canRoundTrip: false}, 159 {escaped: `\u00b7\f\U000000b7`, unEscaped: "·\f·", canRoundTrip: false}, 160 {escaped: `\U000000b7\\\u00b7`, unEscaped: "·\\·", canRoundTrip: false}, 161 {escaped: `\U00010105\\\U00010106`, unEscaped: "\U00010105\\\U00010106", canRoundTrip: true}, 162 } 163 164 func TestUnescape(t *testing.T) { 165 for _, test := range escapeSequenceTests { 166 got := unEscape([]rune(test.escaped)) 167 if got != test.unEscaped { 168 t.Errorf("Failed to properly unescape %q, got:%q want:%q", test.escaped, got, test.unEscaped) 169 } 170 171 if test.canRoundTrip { 172 got = escape("", test.unEscaped, "") 173 if got != test.escaped { 174 t.Errorf("Failed to properly escape %q, got:%q want:%q", test.unEscaped, got, test.escaped) 175 } 176 got = escape(`"`, test.unEscaped, `"`) 177 if got != `"`+test.escaped+`"` { 178 t.Errorf("Failed to properly escape %q quoted, got:%q want:%q", test.unEscaped, got, `"`+test.escaped+`"`) 179 } 180 } 181 } 182 }