├── .gitignore
├── test
├── test.org
├── test.html
└── test.json
├── node.go
├── node_test.go
├── gorg.go
├── gorg_test.go
├── tree.go
└── tree_test.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/test/test.org:
--------------------------------------------------------------------------------
1 | body 0
2 | * headline 1.1
3 | ** headline 1.2
4 | *** headline 1.3
5 | **** headline 1.4
6 | body 1
7 | * headline 2.1
8 | body 2.1.1
9 | body 2.1.2
10 | ** headline 2.2
11 | body 2.2.1
12 | body 2.2.2
13 | *** headline 2.3
14 | body 2
15 | body 2.2
16 | * headline 3.1
17 | body 3.1
18 | body 3.2
19 | body 3.3
--------------------------------------------------------------------------------
/test/test.html:
--------------------------------------------------------------------------------
1 |
headline 1.1
headline 1.2
headline 1.3
headline 1.4
headline 2.1
headline 2.2
headline 2.3
--------------------------------------------------------------------------------
/test/test.json:
--------------------------------------------------------------------------------
1 | {"nodes":[],"subtrees":[{"nodes":[{"headline":"","position":1,"sections":["body 0"]}],"subtrees":null},{"nodes":[{"headline":"headline 1.1","position":1,"sections":null},{"headline":"headline 1.2","position":2,"sections":null},{"headline":"headline 1.3","position":3,"sections":null},{"headline":"headline 1.4","position":4,"sections":["body 1"]}],"subtrees":null},{"nodes":[{"headline":"headline 2.1","position":1,"sections":["body 2.1.1","body 2.1.2"]},{"headline":"headline 2.2","position":2,"sections":["body 2.2.1","body 2.2.2"]},{"headline":"headline 2.3","position":3,"sections":["body 2","body 2.2"]}],"subtrees":null},{"nodes":[{"headline":"headline 3.1","position":1,"sections":[" body 3.1","body 3.2","body 3.3"]}],"subtrees":null}]}
--------------------------------------------------------------------------------
/node.go:
--------------------------------------------------------------------------------
1 | /*
2 | * A Node models an org-mode headline with a following section
3 | * a section can be comprised of multiple lines
4 | * position is the headline's asterisk count
5 | */
6 |
7 | package gorg
8 |
9 | import (
10 | "encoding/json"
11 | "fmt"
12 | )
13 |
14 | type Node struct {
15 | Headline string `json:"headline"`
16 | Position int `json:"position"`
17 | Section []string `json:"sections"`
18 | parent *Node
19 | }
20 |
21 | func (self *Node) findParent(nodes []*Node) *Node {
22 | if len(nodes) == 0 {
23 | return nil
24 | } else if nodes[len(nodes)-1].Position < self.Position {
25 | return nodes[len(nodes)-1]
26 | } else {
27 | nodes = nodes[0 : len(nodes)-1]
28 | return self.findParent(nodes)
29 | }
30 | }
31 |
32 | // the headline gets an tag, with ? determined by the position
33 | // each line of text is a paragraph within a level div
34 | func (self Node) toHtml() string {
35 | var header string
36 |
37 | if self.Headline != "" {
38 | header = fmt.Sprintf(
39 | "%s",
40 | self.Position,
41 | self.Headline,
42 | self.Position,
43 | )
44 | }
45 |
46 | var body string
47 | if len(self.Section) > 0 {
48 | var text string
49 | for _, line := range self.Section {
50 | text = fmt.Sprintf("%s%s
", text, line)
51 | }
52 |
53 | body = fmt.Sprintf(
54 | "%s
",
55 | self.Position,
56 | text,
57 | )
58 | }
59 |
60 | return fmt.Sprintf("%s%s", header, body)
61 | }
62 |
63 | func (self Node) toJson() string {
64 | json, err := json.Marshal(self)
65 | check(err)
66 |
67 | return string(json)
68 | }
69 |
--------------------------------------------------------------------------------
/node_test.go:
--------------------------------------------------------------------------------
1 | package gorg
2 |
3 | import (
4 | "fmt"
5 | "github.com/stretchr/testify/assert"
6 | "testing"
7 | )
8 |
9 | func TestFindParent(t *testing.T) {
10 | fmt.Println("==== Node TestFindParent")
11 |
12 | var node Node
13 | var expected *Node
14 | var parent *Node
15 |
16 | nodes := []*Node{
17 | &Node{Headline: "headline1", Position: 1},
18 | &Node{Headline: "headline2", Position: 2},
19 | &Node{Headline: "headline3", Position: 3},
20 | &Node{Headline: "headline4", Position: 4},
21 | &Node{Headline: "headline5", Position: 3},
22 | &Node{Headline: "headline6", Position: 4},
23 | }
24 |
25 | node = Node{Position: 1}
26 | parent = node.findParent(nodes)
27 | assert.Equal(t, parent, expected)
28 |
29 | node = Node{Position: 2}
30 | parent = node.findParent(nodes)
31 | expected = nodes[0]
32 | assert.Equal(t, parent, expected)
33 |
34 | node = Node{Position: 3}
35 | parent = node.findParent(nodes)
36 | expected = nodes[1]
37 | assert.Equal(t, parent, expected)
38 |
39 | node = Node{Position: 4}
40 | parent = node.findParent(nodes)
41 | expected = nodes[4]
42 | assert.Equal(t, parent, expected)
43 |
44 | node = Node{Position: 5}
45 | parent = node.findParent(nodes)
46 | expected = nodes[5]
47 | assert.Equal(t, parent, expected)
48 | }
49 |
50 | func TestNodeToHtml(t *testing.T) {
51 | fmt.Println("==== Node TestNodeToHtml ")
52 |
53 | var tests = []struct {
54 | in Node
55 | out string
56 | }{
57 | {
58 | in: Node{
59 | Headline: "the headline",
60 | Position: 1,
61 | Section: []string{"the text"},
62 | },
63 | out: "the headline
",
64 | },
65 | {
66 | in: Node{
67 | Headline: "the headline3",
68 | Position: 2,
69 | },
70 | out: "the headline3
",
71 | },
72 | {
73 | in: Node{
74 | Headline: "the headline3",
75 | Position: 4,
76 | },
77 | out: "the headline3
",
78 | },
79 | }
80 |
81 | for _, test := range tests {
82 | actual := test.in.toHtml()
83 | assert.Equal(t, test.out, actual)
84 | }
85 | }
86 |
87 | func TestNodeToJson(t *testing.T) {
88 | fmt.Println("==== Node TestJsonToHtml")
89 |
90 | node := Node{
91 | Headline: "the headline",
92 | Position: 2,
93 | Section: []string{"the text", "more text", "even more"},
94 | }
95 |
96 | expected := "{\"headline\":\"the headline\",\"position\":2,\"sections\":[\"the text\",\"more text\",\"even more\"]}"
97 |
98 | assert.Equal(t, expected, node.toJson())
99 | }
100 |
--------------------------------------------------------------------------------
/gorg.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Converts an org-mode file to a JSON object
3 | * The JSON is a recursive structure - it's subtrees all the way down
4 | * Subtrees contain nodes and more subtrees.
5 | * Properties of a node:
6 | * sections: Paragraphs and code snippets under a headline.
7 | * position: The asterisk count on a headline
8 | * headline: The headline
9 | */
10 |
11 | package gorg
12 |
13 | import (
14 | "bufio"
15 | "io/ioutil"
16 | "os"
17 | "regexp"
18 | )
19 |
20 | func check(e error) {
21 | if e != nil {
22 | panic(e)
23 | }
24 | }
25 |
26 | func OrgToHtmlFile(orgPath string, htmlPath string) {
27 | byteHtml := []byte(OrgToHtml(orgPath))
28 |
29 | err := ioutil.WriteFile(htmlPath, byteHtml, 0644)
30 | check(err)
31 | }
32 |
33 | func TreeFromFile(orgPath string) *Tree {
34 | return NewTree(nodesFromFile(orgPath))
35 | }
36 |
37 | func OrgToHtml(orgPath string) string {
38 | tree := NewTree(nodesFromFile(orgPath))
39 |
40 | return tree.toHtml()
41 | }
42 |
43 | func OrgToJsonFile(orgPath string, jsonPath string) {
44 | byteJson := []byte(OrgToJson(orgPath))
45 |
46 | err := ioutil.WriteFile(jsonPath, byteJson, 0644)
47 | check(err)
48 | }
49 |
50 | func OrgToJson(orgPath string) []byte {
51 | tree := NewTree(nodesFromFile(orgPath))
52 |
53 | return tree.toJson()
54 | }
55 |
56 | // read nodes from the file
57 | // needs to be simplified
58 | // bug: if a table ends the file, it will not be included
59 | func nodesFromFile(path string) []*Node {
60 | file, err := os.Open(path)
61 | check(err)
62 |
63 | defer func() {
64 | check(file.Close())
65 | }()
66 |
67 | scanner := bufio.NewScanner(file)
68 | var node *Node
69 | var nodes []*Node
70 | var headline string
71 | var position int
72 | var section string
73 | var isBlock bool
74 | var isCodeBlock bool
75 | var isTable bool
76 |
77 | for scanner.Scan() {
78 | line := scanner.Text()
79 |
80 | r := regexp.MustCompile(`\A(\*+)\ (.*)`) // should use \S
81 | submatch := r.FindStringSubmatch(line)
82 |
83 | if len(submatch) > 1 {
84 | isBlock = false
85 | isCodeBlock = false
86 | isTable = false
87 |
88 | headline = submatch[2]
89 | position = len(submatch[1])
90 |
91 | node = &Node{Headline: headline, Position: position}
92 |
93 | node.parent = node.findParent(nodes)
94 | nodes = append(nodes, node)
95 | } else {
96 | codeStartReg := regexp.MustCompile(`\A(\#\+BEGIN_SRC)(.*)`)
97 | codeEndReg := regexp.MustCompile(`\A(\#\+END_SRC)`)
98 |
99 | tableReg := regexp.MustCompile(`\A\s*\|.*`)
100 |
101 | if codeStartReg.MatchString(line) {
102 | isCodeBlock = true
103 | } else if codeEndReg.MatchString(line) {
104 | isCodeBlock = false
105 | }
106 |
107 | isTable = tableReg.MatchString(line) && !isCodeBlock
108 | isBlock = isCodeBlock || isTable
109 |
110 | section += line
111 |
112 | if !isBlock {
113 | if len(nodes) == 0 {
114 | nodes = []*Node{&Node{Position: 1, Section: []string{section}}}
115 | } else {
116 | lastNode := nodes[len(nodes)-1]
117 | lastNode.Section = append(lastNode.Section, section)
118 | }
119 | section = ""
120 | }
121 | }
122 | }
123 |
124 | return nodes
125 | }
126 |
--------------------------------------------------------------------------------
/gorg_test.go:
--------------------------------------------------------------------------------
1 | package gorg
2 |
3 | import (
4 | "fmt"
5 | "github.com/stretchr/testify/assert"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "testing"
10 | )
11 |
12 | func TestNodesFromFile(t *testing.T) {
13 | fmt.Println("==== gorg TestNodesFromFile")
14 | path, _ := filepath.Abs("test/test.org")
15 |
16 | tree := NewTree(nodesFromFile(path))
17 |
18 | assert.Equal(t, 0, len(tree.Nodes))
19 | assert.Equal(t, 4, len(tree.Subtrees))
20 |
21 | expected := "headline 1.1
headline 1.2
headline 1.3
headline 1.4
headline 2.1
headline 2.2
headline 2.3
"
22 |
23 | assert.Equal(t, tree.toHtml(), expected)
24 | }
25 |
26 | func TestOrgToHtmlFile(t *testing.T) {
27 | fmt.Println("==== gorg testOrgToHtmlFile")
28 |
29 | inPath, _ := filepath.Abs("test/test.org")
30 | outPath, _ := filepath.Abs("test/test.html")
31 |
32 | // remove last test file, if exists
33 | if _, err := os.Stat(outPath); err == nil {
34 | os.Remove(outPath)
35 | }
36 |
37 | OrgToHtmlFile(inPath, outPath)
38 |
39 | htmlFileContents, _ := ioutil.ReadFile(outPath)
40 | contents := htmlFileContents
41 |
42 | expected := "headline 1.1
headline 1.2
headline 1.3
headline 1.4
headline 2.1
headline 2.2
headline 2.3
"
43 |
44 | assert.Equal(t, string(contents), expected)
45 | }
46 |
47 | func TestOrgToJsonFile(t *testing.T) {
48 | fmt.Println("==== gorg testOrgToJsonFile")
49 |
50 | inPath, _ := filepath.Abs("test/test.org")
51 | outPath, _ := filepath.Abs("test/test.json")
52 |
53 | // remove last test file
54 | if _, err := os.Stat(outPath); err == nil {
55 | os.Remove(outPath)
56 | }
57 |
58 | OrgToJsonFile(inPath, outPath)
59 |
60 | jsonFileContents, _ := ioutil.ReadFile(outPath)
61 | contents := jsonFileContents
62 |
63 | expected := "{\"nodes\":[],\"subtrees\":[{\"nodes\":[{\"headline\":\"\",\"position\":1,\"sections\":[\"body 0\"]}],\"subtrees\":null},{\"nodes\":[{\"headline\":\"headline 1.1\",\"position\":1,\"sections\":null},{\"headline\":\"headline 1.2\",\"position\":2,\"sections\":null},{\"headline\":\"headline 1.3\",\"position\":3,\"sections\":null},{\"headline\":\"headline 1.4\",\"position\":4,\"sections\":[\"body 1\"]}],\"subtrees\":null},{\"nodes\":[{\"headline\":\"headline 2.1\",\"position\":1,\"sections\":[\"body 2.1.1\",\"body 2.1.2\"]},{\"headline\":\"headline 2.2\",\"position\":2,\"sections\":[\"body 2.2.1\",\"body 2.2.2\"]},{\"headline\":\"headline 2.3\",\"position\":3,\"sections\":[\"body 2\",\"body 2.2\"]}],\"subtrees\":null},{\"nodes\":[{\"headline\":\"headline 3.1\",\"position\":1,\"sections\":[\" body 3.1\",\"body 3.2\",\"body 3.3\"]}],\"subtrees\":null}]}"
64 |
65 | assert.Equal(t, string(contents), expected)
66 | }
67 |
--------------------------------------------------------------------------------
/tree.go:
--------------------------------------------------------------------------------
1 | package gorg
2 |
3 | import "fmt"
4 | import "encoding/json"
5 |
6 | type Tree struct {
7 | Nodes []*Node `json:"nodes"`
8 | Subtrees []*Tree `json:"subtrees"`
9 | parent *Tree
10 | }
11 |
12 | func NewTree(nodes []*Node) *Tree {
13 | tree := Tree{Nodes: nodes}
14 | tree.unflatten()
15 |
16 | return &tree
17 | }
18 |
19 | func (self *Tree) addNode(node *Node) {
20 | node.parent = node.findParent(self.Nodes)
21 |
22 | if node.Position == 0 {
23 | node.Position = 1
24 | }
25 |
26 | self.Nodes = append(self.Nodes, node)
27 | }
28 |
29 | func (self *Tree) addSubtree(subtree *Tree) {
30 | subtree.parent = self
31 | self.Subtrees = append(self.Subtrees, subtree)
32 | }
33 |
34 | func (self Tree) isEmpty() bool {
35 | return len(self.Nodes) == 0
36 | }
37 |
38 | func (self Tree) lastNode() *Node {
39 | return self.Nodes[len(self.Nodes)-1]
40 | }
41 |
42 | func (self Tree) toHtml() string {
43 | var html string
44 |
45 | // if top level of tree has Nodes,
46 | // top is one, collapsible subtree
47 | if len(self.Nodes) > 1 {
48 | html = ""
49 | }
50 | html = self.subtreesToHtml(html)
51 |
52 | if len(self.Nodes) > 1 {
53 | html = html + "
"
54 | }
55 |
56 | return html
57 | }
58 |
59 | func (self Tree) subtreesToHtml(html string) string {
60 |
61 | for _, node := range self.Nodes {
62 | html = fmt.Sprintf("%s%s", html, node.toHtml())
63 | }
64 |
65 | for _, subtree := range self.Subtrees {
66 | html = html + ""
67 | html = subtree.subtreesToHtml(html)
68 | html = html + "
"
69 | }
70 |
71 | return html
72 | }
73 |
74 | func (self Tree) toJson() []byte {
75 | json, err := json.Marshal(self)
76 | check(err)
77 |
78 | return json
79 | }
80 |
81 | func (self *Tree) indexOfNode(searchNode *Node) int {
82 | for i, node := range self.Nodes {
83 | if node == searchNode {
84 | return i
85 | }
86 | }
87 |
88 | return -1
89 | }
90 |
91 | func (self *Tree) deleteNode(node *Node) {
92 | i := self.indexOfNode(node)
93 |
94 | if i == -1 {
95 | return
96 | }
97 |
98 | if i == 0 {
99 | self.Nodes = self.Nodes[1:]
100 | } else if i == len(self.Nodes)-1 {
101 | self.Nodes = self.Nodes[:len(self.Nodes)-1]
102 | } else {
103 | self.Nodes = append(self.Nodes[:i], self.Nodes[i+1:]...)
104 | }
105 | }
106 |
107 | func (self *Tree) unflatten() {
108 | subtrees := getSubtrees(self.Nodes)
109 |
110 | for _, s := range subtrees {
111 | self.addSubtree(s)
112 |
113 | for _, n := range s.Nodes {
114 | self.deleteNode(n)
115 | }
116 | }
117 |
118 | for _, subtree := range self.Subtrees {
119 | subtree.unflatten()
120 | }
121 | }
122 |
123 | func getSubtrees(ns []*Node) []*Tree {
124 |
125 | if len(ns) == 1 {
126 | return []*Tree{}
127 | }
128 |
129 | root := ns[0]
130 | nodes := ns[1:]
131 |
132 | subtree := &Tree{Nodes: []*Node{root}}
133 | var subtrees []*Tree
134 |
135 | for _, node := range nodes {
136 | if node.Position > root.Position {
137 | subtree.addNode(node)
138 | } else {
139 | subtrees = append(subtrees, subtree)
140 |
141 | root = node
142 |
143 | subtree = &Tree{Nodes: []*Node{root}}
144 |
145 | }
146 |
147 | if node == nodes[len(nodes)-1] {
148 | subtrees = append(subtrees, subtree)
149 | }
150 | }
151 |
152 | if len(subtrees) > 1 {
153 | return subtrees
154 | } else {
155 | return getSubtrees(nodes)
156 | }
157 | }
158 |
159 | func printTree(tree Tree) {
160 | for _, node := range tree.Nodes {
161 | line := ""
162 | for i := 0; i < node.Position; i++ {
163 | line = line + "*"
164 | }
165 |
166 | line = line + " " + node.Headline
167 | fmt.Println(line)
168 | }
169 |
170 | for _, subtree := range tree.Subtrees {
171 | printTree(*subtree)
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/tree_test.go:
--------------------------------------------------------------------------------
1 | package gorg
2 |
3 | import (
4 | "fmt"
5 | "github.com/stretchr/testify/assert"
6 | "testing"
7 | )
8 |
9 | func TestIsEmpty(t *testing.T) {
10 | fmt.Println("==== Tree TestisEmpty")
11 |
12 | var testTree Tree
13 |
14 | assert.True(t, testTree.isEmpty())
15 |
16 | testTree = Tree{Nodes: []*Node{&Node{Headline: "test"}}}
17 |
18 | assert.False(t, testTree.isEmpty())
19 | }
20 |
21 | func TestAddNode(t *testing.T) {
22 | fmt.Println("==== Tree TestAddNode")
23 |
24 | var tree Tree
25 |
26 | assert.True(t, tree.isEmpty())
27 |
28 | node1 := &Node{Headline: "test node1", Position: 1}
29 | tree.addNode(node1)
30 |
31 | assert.False(t, tree.isEmpty())
32 | assert.Equal(t, tree.Nodes[0].Headline, "test node1")
33 |
34 | node2 := &Node{Headline: "test node2", Position: 3}
35 | tree.addNode(node2)
36 | assert.Equal(t, tree.Nodes[0].Headline, "test node1")
37 | assert.Equal(t, tree.Nodes[1].Headline, "test node2")
38 |
39 | node3 := &Node{Headline: "test node3", Position: 2}
40 | tree.addNode(node3)
41 | assert.Equal(t, tree.Nodes[0].Headline, "test node1")
42 | assert.Equal(t, tree.Nodes[1].Headline, "test node2")
43 | assert.Equal(t, tree.Nodes[2].Headline, "test node3")
44 |
45 | node4 := &Node{Headline: "test node4", Position: 4}
46 | tree.addNode(node4)
47 | assert.Equal(t, tree.Nodes[0].Headline, "test node1")
48 | assert.Equal(t, tree.Nodes[1].Headline, "test node2")
49 | assert.Equal(t, tree.Nodes[2].Headline, "test node3")
50 | assert.Equal(t, tree.Nodes[3].Headline, "test node4")
51 |
52 | node5 := &Node{Headline: "test node5", Position: 5}
53 | tree.addNode(node5)
54 | assert.Equal(t, tree.Nodes[0].Headline, "test node1")
55 | assert.Equal(t, tree.Nodes[1].Headline, "test node2")
56 | assert.Equal(t, tree.Nodes[2].Headline, "test node3")
57 | assert.Equal(t, tree.Nodes[3].Headline, "test node4")
58 | assert.Equal(t, tree.Nodes[4].Headline, "test node5")
59 |
60 | var parent *Node
61 | assert.Equal(t, tree.Nodes[0].parent, parent)
62 | assert.Equal(t, tree.Nodes[1].parent, node1)
63 | assert.Equal(t, tree.Nodes[2].parent, node1)
64 | assert.Equal(t, tree.Nodes[3].parent, node3)
65 | assert.Equal(t, tree.Nodes[4].parent, node4)
66 | }
67 |
68 | func TestAddSubtree(t *testing.T) {
69 | fmt.Println("==== Tree TestSubtree")
70 |
71 | var tree Tree
72 |
73 | subtree1 := Tree{Nodes: []*Node{&Node{Headline: "test"}}}
74 | tree.addSubtree(&subtree1)
75 |
76 | subtree2 := Tree{Nodes: []*Node{&Node{Headline: "test"}}}
77 | tree.addSubtree(&subtree2)
78 |
79 | subtree3 := Tree{Nodes: []*Node{&Node{Headline: "test"}}}
80 | tree.addSubtree(&subtree3)
81 |
82 | subtree4 := Tree{Nodes: []*Node{&Node{Headline: "test"}}}
83 | tree.addSubtree(&subtree4)
84 |
85 | assert.Equal(t, tree.Subtrees[0], &subtree1)
86 | assert.Equal(t, tree.Subtrees[1], &subtree2)
87 | assert.Equal(t, tree.Subtrees[2], &subtree3)
88 | assert.Equal(t, tree.Subtrees[3], &subtree4)
89 |
90 | assert.Equal(t, tree.Subtrees[0].parent, &tree)
91 | assert.Equal(t, tree.Subtrees[1].parent, &tree)
92 | assert.Equal(t, tree.Subtrees[2].parent, &tree)
93 | assert.Equal(t, tree.Subtrees[3].parent, &tree)
94 | }
95 |
96 | func TestTreeToHtml(t *testing.T) {
97 | fmt.Println("==== Tree TestTreeToHtml")
98 |
99 | node1 := &Node{Headline: "headline1", Position: 1}
100 | node2 := &Node{
101 | Headline: "headline2",
102 | Position: 2,
103 | Section: []string{"the section for node2"},
104 | parent: node1,
105 | }
106 | node3 := &Node{Headline: "headline3", Position: 3, parent: node2}
107 | node4 := &Node{
108 | Headline: "headline4",
109 | Position: 4,
110 | Section: []string{"the section for node4"},
111 | parent: node3,
112 | }
113 | node5 := &Node{Headline: "headline5", Position: 3, parent: node2}
114 | node6 := &Node{
115 | Headline: "headline6",
116 | Position: 4,
117 | Section: []string{"the section for node6", "some more text"},
118 | parent: node5,
119 | }
120 |
121 | nodes := []*Node{node1, node2, node3, node4, node5, node6}
122 | tree := NewTree(nodes)
123 | html := tree.toHtml()
124 |
125 | var tests = []struct {
126 | in string
127 | out string
128 | }{
129 | {
130 | in: html,
131 | out: "headline1
headline2
headline5
headline6
the section for node6
some more text
",
132 | },
133 | }
134 |
135 | for _, test := range tests {
136 | assert.Equal(t, test.out, test.in)
137 | }
138 | }
139 |
140 | func TestTreeToJson(t *testing.T) {
141 | fmt.Println("==== Tree TestTreeToJson")
142 |
143 | node1 := &Node{Headline: "headline1", Position: 1}
144 | node2 := &Node{
145 | Headline: "headline2",
146 | Position: 2,
147 | Section: []string{"the section for node2"},
148 | parent: node1,
149 | }
150 | node3 := &Node{Headline: "headline3", Position: 3, parent: node2}
151 | node4 := &Node{
152 | Headline: "headline4",
153 | Position: 4,
154 | Section: []string{"the section for node4"},
155 | parent: node3,
156 | }
157 | node5 := &Node{Headline: "headline5", Position: 3, parent: node2}
158 | node6 := &Node{
159 | Headline: "headline6",
160 | Position: 4,
161 | Section: []string{"the section for node6", "some more text"},
162 | parent: node5,
163 | }
164 |
165 | nodes := []*Node{node1, node2, node3, node4, node5, node6}
166 | tree := NewTree(nodes)
167 | json := string(tree.toJson())
168 |
169 | var tests = []struct {
170 | in string
171 | out string
172 | }{
173 | {
174 | in: json,
175 | out: "{\"nodes\":[{\"headline\":\"headline1\",\"position\":1,\"sections\":null},{\"headline\":\"headline2\",\"position\":2,\"sections\":[\"the section for node2\"]}],\"subtrees\":[{\"nodes\":[{\"headline\":\"headline3\",\"position\":3,\"sections\":null},{\"headline\":\"headline4\",\"position\":4,\"sections\":[\"the section for node4\"]}],\"subtrees\":null},{\"nodes\":[{\"headline\":\"headline5\",\"position\":3,\"sections\":null},{\"headline\":\"headline6\",\"position\":4,\"sections\":[\"the section for node6\",\"some more text\"]}],\"subtrees\":null}]}",
176 | },
177 | }
178 |
179 | for _, test := range tests {
180 | assert.Equal(t, test.out, test.in)
181 | }
182 | }
183 |
184 | func TestIndexOfNode(t *testing.T) {
185 | fmt.Println("==== Tree TestIndexOfNode")
186 |
187 | node1 := &Node{Headline: "headline1", Position: 1}
188 | node2 := &Node{Headline: "headline2", Position: 2}
189 | node3 := &Node{Headline: "headline3", Position: 3}
190 | node4 := &Node{Headline: "headline4", Position: 4}
191 |
192 | tree := Tree{Nodes: []*Node{node1, node2, node3, node4}}
193 |
194 | assert.Equal(t, tree.indexOfNode(node4), 3)
195 | assert.Equal(t, tree.indexOfNode(node1), 0)
196 | assert.Equal(t, tree.indexOfNode(node2), 1)
197 | assert.Equal(t, tree.indexOfNode(node3), 2)
198 | }
199 |
200 | func TestDeleteNode(t *testing.T) {
201 | fmt.Println("==== Tree TestDeleteNode")
202 |
203 | node1 := &Node{Headline: "headline1", Position: 1}
204 | node2 := &Node{Headline: "headline2", Position: 2}
205 | node3 := &Node{Headline: "headline3", Position: 3}
206 | node4 := &Node{Headline: "headline4", Position: 4}
207 |
208 | tree := Tree{Nodes: []*Node{node1, node2, node3, node4}}
209 |
210 | assert.Equal(t, len(tree.Nodes), 4)
211 |
212 | tree.deleteNode(node2)
213 |
214 | assert.Equal(t, len(tree.Nodes), 3)
215 | assert.Equal(t, tree.Nodes[0].Headline, "headline1")
216 | assert.Equal(t, tree.Nodes[1].Headline, "headline3")
217 | assert.Equal(t, tree.Nodes[2].Headline, "headline4")
218 |
219 | tree.deleteNode(node1)
220 |
221 | assert.Equal(t, len(tree.Nodes), 2)
222 | assert.Equal(t, tree.Nodes[0].Headline, "headline3")
223 | assert.Equal(t, tree.Nodes[1].Headline, "headline4")
224 |
225 | tree.deleteNode(node4)
226 |
227 | assert.Equal(t, len(tree.Nodes), 1)
228 | assert.Equal(t, tree.Nodes[0].Headline, "headline3")
229 |
230 | tree.deleteNode(node3)
231 |
232 | assert.Equal(t, len(tree.Nodes), 0)
233 | }
234 |
235 | func TestUnflattenTree(t *testing.T) {
236 | fmt.Println("==== Tree TestUnflattenTree")
237 |
238 | var tree Tree
239 |
240 | tree.addNode(&Node{Headline: "sub0.0.1", Position: 2})
241 | tree.addNode(&Node{Headline: "sub1.1.1", Position: 1})
242 | tree.addNode(&Node{Headline: "sub1.1.2", Position: 2})
243 | tree.addNode(&Node{Headline: "sub1.1.3", Position: 3})
244 | tree.addNode(&Node{Headline: "sub2.1.1", Position: 1})
245 | tree.addNode(&Node{Headline: "sub2.1.2", Position: 3})
246 | tree.addNode(&Node{Headline: "sub2.2.1", Position: 4})
247 | tree.addNode(&Node{Headline: "sub2.2.2", Position: 5})
248 | tree.addNode(&Node{Headline: "sub2.3.1", Position: 4})
249 | tree.addNode(&Node{Headline: "sub2.3.2", Position: 5})
250 | tree.addNode(&Node{Headline: "sub2.3.3", Position: 6})
251 | tree.addNode(&Node{Headline: "sub2.4.1", Position: 4})
252 | tree.addNode(&Node{Headline: "sub2.4.2", Position: 5})
253 | tree.addNode(&Node{Headline: "sub3.1.1", Position: 1})
254 |
255 | // ** sub0.1.1
256 | // * sub1.1.1
257 | // ** sub1.1.2
258 | // *** sub1.1.3
259 | // * sub2.1.1
260 | // *** sub2.1.2
261 | // **** sub2.2.1
262 | // ***** sub2.2.2
263 | // **** sub2.3.1
264 | // ***** sub2.3.2
265 | // ****** sub2.3.3
266 | // **** sub2.4.1
267 | // ***** sub2.4.2
268 | // * sub3.1.1
269 |
270 | tree.unflatten()
271 |
272 | assert.Equal(t, len(tree.Nodes), 0)
273 | assert.Equal(t, len(tree.Subtrees), 4)
274 |
275 | sub01 := tree.Subtrees[0]
276 | assert.Equal(t, len(sub01.Nodes), 1)
277 | assert.Equal(t, len(sub01.Subtrees), 0)
278 |
279 | assert.Equal(t, sub01.Nodes[0].Headline, "sub0.0.1")
280 |
281 | sub11 := tree.Subtrees[1]
282 | assert.Equal(t, len(sub11.Nodes), 3)
283 | assert.Equal(t, len(sub11.Subtrees), 0)
284 |
285 | assert.Equal(t, sub11.Nodes[0].Headline, "sub1.1.1")
286 | assert.Equal(t, sub11.Nodes[1].Headline, "sub1.1.2")
287 | assert.Equal(t, sub11.Nodes[2].Headline, "sub1.1.3")
288 |
289 | sub21 := tree.Subtrees[2]
290 | assert.Equal(t, len(sub21.Nodes), 2)
291 | assert.Equal(t, len(sub21.Subtrees), 3)
292 |
293 | assert.Equal(t, sub21.Nodes[0].Headline, "sub2.1.1")
294 | assert.Equal(t, sub21.Nodes[1].Headline, "sub2.1.2")
295 |
296 | sub22 := tree.Subtrees[2].Subtrees[0]
297 | assert.Equal(t, len(sub22.Nodes), 2)
298 | assert.Equal(t, len(sub22.Subtrees), 0)
299 |
300 | assert.Equal(t, sub22.Nodes[0].Headline, "sub2.2.1")
301 | assert.Equal(t, sub22.Nodes[1].Headline, "sub2.2.2")
302 |
303 | sub23 := tree.Subtrees[2].Subtrees[1]
304 | assert.Equal(t, len(sub23.Nodes), 3)
305 | assert.Equal(t, len(sub23.Subtrees), 0)
306 |
307 | assert.Equal(t, sub23.Nodes[0].Headline, "sub2.3.1")
308 | assert.Equal(t, sub23.Nodes[1].Headline, "sub2.3.2")
309 | assert.Equal(t, sub23.Nodes[2].Headline, "sub2.3.3")
310 |
311 | sub24 := tree.Subtrees[2].Subtrees[2]
312 | assert.Equal(t, len(sub24.Nodes), 2)
313 | assert.Equal(t, len(sub24.Subtrees), 0)
314 |
315 | assert.Equal(t, sub24.Nodes[0].Headline, "sub2.4.1")
316 | assert.Equal(t, sub24.Nodes[1].Headline, "sub2.4.2")
317 |
318 | sub31 := tree.Subtrees[3]
319 | assert.Equal(t, len(sub31.Nodes), 1)
320 | assert.Equal(t, len(sub31.Subtrees), 0)
321 |
322 | assert.Equal(t, sub31.Nodes[0].Headline, "sub3.1.1")
323 | }
324 |
--------------------------------------------------------------------------------