1package bpdoc
2
3import (
4	"fmt"
5	"reflect"
6	"testing"
7)
8
9type propInfo struct {
10	name string
11	typ  string
12}
13
14type parentProps struct {
15	A string
16
17	Child *childProps
18
19	Mutated *mutatedProps `blueprint:"mutated"`
20}
21
22type childProps struct {
23	B int
24
25	Child *grandchildProps
26}
27
28type grandchildProps struct {
29	C bool
30}
31
32type mutatedProps struct {
33	D int
34}
35
36func TestNestedPropertyStructs(t *testing.T) {
37	parent := parentProps{Child: &childProps{Child: &grandchildProps{}}, Mutated: &mutatedProps{}}
38
39	allStructs := nestedPropertyStructs(reflect.ValueOf(parent))
40
41	// mutated shouldn't be found because it's a mutated property.
42	expected := []string{"child", "child.child"}
43	if len(allStructs) != len(expected) {
44		t.Fatalf("expected %d structs, got %d, all entries: %v",
45			len(expected), len(allStructs), allStructs)
46	}
47	got := []string{}
48	for _, s := range allStructs {
49		got = append(got, s.nestPoint)
50	}
51
52	if !reflect.DeepEqual(got, expected) {
53		t.Errorf("Expected nested properties:\n\t %q,\n but got\n\t %q", expected, got)
54	}
55}
56
57func TestAllPackages(t *testing.T) {
58	packages, err := AllPackages(pkgFiles, moduleTypeNameFactories, moduleTypeNamePropertyStructs)
59	if err != nil {
60		t.Fatalf("expected nil error for AllPackages(%v, %v, %v), got %s", pkgFiles, moduleTypeNameFactories, moduleTypeNamePropertyStructs, err)
61	}
62
63	if numPackages := len(packages); numPackages != 1 {
64		t.Errorf("Expected %d package, got %d packages %v instead", len(pkgFiles), numPackages, packages)
65	}
66
67	pkg := packages[0]
68
69	expectedProps := map[string][]propInfo{
70		"bar": []propInfo{
71			propInfo{
72				name: "a",
73				typ:  "string",
74			},
75			propInfo{
76				name: "nested",
77				typ:  "",
78			},
79			propInfo{
80				name: "nested.c",
81				typ:  "string",
82			},
83			propInfo{
84				name: "nested_struct",
85				typ:  "structToNest",
86			},
87			propInfo{
88				name: "nested_struct.e",
89				typ:  "string",
90			},
91			propInfo{
92				name: "struct_has_embed",
93				typ:  "StructWithEmbedded",
94			},
95			propInfo{
96				name: "struct_has_embed.nested_in_embedded",
97				typ:  "structToNest",
98			},
99			propInfo{
100				name: "struct_has_embed.nested_in_embedded.e",
101				typ:  "string",
102			},
103			propInfo{
104				name: "struct_has_embed.f",
105				typ:  "string",
106			},
107			propInfo{
108				name: "list_of_ints",
109				typ:  "list of int",
110			},
111			propInfo{
112				name: "list_of_nested",
113				typ:  "list of structToNest",
114			},
115			propInfo{
116				name: "nested_in_other_embedded",
117				typ:  "otherStructToNest",
118			},
119			propInfo{
120				name: "nested_in_other_embedded.g",
121				typ:  "string",
122			},
123			propInfo{
124				name: "h",
125				typ:  "string",
126			},
127		},
128		"foo": []propInfo{
129			propInfo{
130				name: "a",
131				typ:  "string",
132			},
133		},
134	}
135
136	for _, m := range pkg.ModuleTypes {
137		foundProps := []propInfo{}
138
139		for _, p := range m.PropertyStructs {
140			nestedProps, errs := findAllProperties("", p.Properties)
141			foundProps = append(foundProps, nestedProps...)
142			for _, err := range errs {
143				t.Errorf("%s", err)
144			}
145		}
146		if wanted, ok := expectedProps[m.Name]; ok {
147			if !reflect.DeepEqual(foundProps, wanted) {
148				t.Errorf("For %s, expected\n\t %q,\nbut got\n\t %q", m.Name, wanted, foundProps)
149			}
150		}
151	}
152}
153
154func findAllProperties(prefix string, properties []Property) ([]propInfo, []error) {
155	foundProps := []propInfo{}
156	errs := []error{}
157	for _, p := range properties {
158		prop := propInfo{
159			name: prefix + p.Name,
160			typ:  p.Type,
161		}
162		foundProps = append(foundProps, prop)
163		if hasTag(p.Tag, "blueprint", "mutated") {
164			err := fmt.Errorf("Property %s has `blueprint:\"mutated\" tag but should have been excluded.", p.Name)
165			errs = append(errs, err)
166		}
167
168		nestedProps, nestedErrs := findAllProperties(prefix+p.Name+".", p.Properties)
169		foundProps = append(foundProps, nestedProps...)
170		errs = append(errs, nestedErrs...)
171	}
172	return foundProps, errs
173}
174