Migration
This is my new public git source viewer. Source coming soon. Please contact with concerns/bugs.
Contact me
internal/modules/structured_test.go
c0427d5fc7c0fcf8606c546071085e8af231fb81
· 3.7 KB · 158 lines
raw
| 1 | package modules |
| 2 | |
| 3 | import ( |
| 4 | "html/template" |
| 5 | "strings" |
| 6 | "testing" |
| 7 | ) |
| 8 | |
| 9 | // lines builds the Line slice annotateStructure expects, mirroring what |
| 10 | // blobMod produces before the structure pass runs. |
| 11 | func lines(raw string) []Line { |
| 12 | out := []Line{} |
| 13 | for i, t := range strings.Split(raw, "\n") { |
| 14 | out = append(out, Line{N: i + 1, Text: template.HTML(t)}) |
| 15 | } |
| 16 | return out |
| 17 | } |
| 18 | |
| 19 | const sampleYAML = `defaults: &defaults |
| 20 | adapter: postgres |
| 21 | pool: 5 |
| 22 | |
| 23 | development: |
| 24 | <<: *defaults |
| 25 | database: dev |
| 26 | |
| 27 | test: |
| 28 | <<: *defaults |
| 29 | database: test |
| 30 | hosts: |
| 31 | - a |
| 32 | - b |
| 33 | ` |
| 34 | |
| 35 | func TestFoldRangesYAML(t *testing.T) { |
| 36 | ls := lines(sampleYAML) |
| 37 | annotateStructure(ls, []byte(sampleYAML), "yaml") |
| 38 | |
| 39 | want := map[int]int{ |
| 40 | 1: 3, // defaults: block ends at "pool: 5", not the blank line after |
| 41 | 5: 7, // development: |
| 42 | 9: 14, // test:, stopping short of the empty line 15 |
| 43 | 12: 14, // hosts: |
| 44 | } |
| 45 | for _, l := range ls { |
| 46 | if got, ok := want[l.N]; ok { |
| 47 | if l.FoldTo != got { |
| 48 | t.Errorf("line %d: FoldTo = %d, want %d", l.N, l.FoldTo, got) |
| 49 | } |
| 50 | } else if l.FoldTo != 0 { |
| 51 | t.Errorf("line %d: FoldTo = %d, want none", l.N, l.FoldTo) |
| 52 | } |
| 53 | } |
| 54 | if ls[1].Depth != 1 { |
| 55 | t.Errorf("line 2 depth = %d, want 1", ls[1].Depth) |
| 56 | } |
| 57 | if ls[13].Depth != 2 { |
| 58 | t.Errorf("line 14 depth = %d, want 2", ls[13].Depth) |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | func TestKeysAndAnchors(t *testing.T) { |
| 63 | ls := lines(sampleYAML) |
| 64 | annotateStructure(ls, []byte(sampleYAML), "yaml") |
| 65 | |
| 66 | if ls[0].Key != "defaults" { |
| 67 | t.Errorf("line 1 key = %q, want %q", ls[0].Key, "defaults") |
| 68 | } |
| 69 | if ls[13].Key != "" { |
| 70 | t.Errorf("line 14 (sequence item) key = %q, want none", ls[13].Key) |
| 71 | } |
| 72 | |
| 73 | // The anchor is reported on the line the &token is written on, not on |
| 74 | // the line the mapping it names begins. |
| 75 | a := ls[0].Anchor |
| 76 | if a == nil { |
| 77 | t.Fatal("line 1: no anchor") |
| 78 | } |
| 79 | if a.Name != "defaults" || a.Uses != 2 { |
| 80 | t.Errorf("anchor = %+v, want {defaults 2}", *a) |
| 81 | } |
| 82 | |
| 83 | for _, n := range []int{6, 10} { |
| 84 | r := ls[n-1].Ref |
| 85 | if r == nil { |
| 86 | t.Fatalf("line %d: no ref", n) |
| 87 | } |
| 88 | if r.Name != "defaults" || r.Line != 1 { |
| 89 | t.Errorf("line %d ref = %+v, want defaults@1", n, *r) |
| 90 | } |
| 91 | if !strings.Contains(r.Preview, "adapter: postgres") { |
| 92 | t.Errorf("line %d preview = %q, want the resolved mapping", n, r.Preview) |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | // Anchors defined in the second document of a stream are still resolved: |
| 98 | // yaml.Unmarshal would only ever see the first. |
| 99 | func TestMultiDocumentAnchors(t *testing.T) { |
| 100 | const src = `--- |
| 101 | kind: First |
| 102 | --- |
| 103 | base: &b |
| 104 | x: 1 |
| 105 | copy: *b |
| 106 | ` |
| 107 | ls := lines(src) |
| 108 | annotateStructure(ls, []byte(src), "yaml") |
| 109 | |
| 110 | if ls[3].Anchor == nil || ls[3].Anchor.Name != "b" { |
| 111 | t.Fatalf("line 4 anchor = %+v, want b", ls[3].Anchor) |
| 112 | } |
| 113 | if r := ls[5].Ref; r == nil || r.Line != 4 { |
| 114 | t.Fatalf("line 6 ref = %+v, want b@4", r) |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | func TestFoldRangesJSON(t *testing.T) { |
| 119 | const src = `{ |
| 120 | "name": "gsg", |
| 121 | "deps": { |
| 122 | "a": 1 |
| 123 | }, |
| 124 | "list": [ |
| 125 | 2 |
| 126 | ] |
| 127 | }` |
| 128 | ls := lines(src) |
| 129 | annotateStructure(ls, []byte(src), "json") |
| 130 | |
| 131 | if ls[0].FoldTo != 8 { |
| 132 | t.Errorf("line 1 FoldTo = %d, want 8", ls[0].FoldTo) |
| 133 | } |
| 134 | if ls[2].FoldTo != 4 { |
| 135 | t.Errorf("line 3 FoldTo = %d, want 4", ls[2].FoldTo) |
| 136 | } |
| 137 | if ls[5].FoldTo != 7 { |
| 138 | t.Errorf("line 6 FoldTo = %d, want 7", ls[5].FoldTo) |
| 139 | } |
| 140 | if ls[1].Key != "name" { |
| 141 | t.Errorf("line 2 key = %q, want %q", ls[1].Key, "name") |
| 142 | } |
| 143 | // No anchors outside YAML, and a brace inside a string is not structure. |
| 144 | if ls[1].Anchor != nil || ls[1].Ref != nil { |
| 145 | t.Error("JSON line carries anchor/ref data") |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | // Minified JSON has no indentation to fold on; it must degrade to a plain |
| 150 | // view rather than producing bogus ranges. |
| 151 | func TestMinifiedJSONHasNoFolds(t *testing.T) { |
| 152 | const src = `{"a":{"b":[1,2]},"c":3}` |
| 153 | ls := lines(src) |
| 154 | annotateStructure(ls, []byte(src), "json") |
| 155 | if ls[0].FoldTo != 0 { |
| 156 | t.Errorf("FoldTo = %d, want 0", ls[0].FoldTo) |
| 157 | } |
| 158 | } |