1// Copyright 2019 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// bpdoc docs. 16package bpdoc 17 18import ( 19 "html/template" 20 "reflect" 21 "runtime" 22 "testing" 23 24 "github.com/google/blueprint" 25) 26 27type factoryFn func() (blueprint.Module, []interface{}) 28 29// foo docs. 30func fooFactory() (blueprint.Module, []interface{}) { 31 return nil, []interface{}{&props{}} 32} 33 34// bar docs. 35func barFactory() (blueprint.Module, []interface{}) { 36 return nil, []interface{}{&complexProps{}} 37} 38 39type structToNest struct { 40 E string 41} 42 43type StructToEmbed struct { 44 Nested_in_embedded structToNest 45 46 // F string 47 F string 48} 49 50type otherStructToNest struct { 51 G string 52} 53 54type OtherStructToEmbed struct { 55 Nested_in_other_embedded otherStructToNest 56 57 // F string 58 H string 59} 60 61type StructWithEmbedded struct { 62 StructToEmbed 63} 64 65// for bpdoc_test.go 66type complexProps struct { 67 A string 68 B_mutated string `blueprint:"mutated"` 69 70 Nested struct { 71 C string 72 D_mutated string `blueprint:"mutated"` 73 } 74 75 Nested_struct structToNest 76 77 Struct_has_embed StructWithEmbedded 78 79 OtherStructToEmbed 80 81 List_of_ints []int 82 83 List_of_nested []structToNest 84} 85 86// props docs. 87type props struct { 88 // A docs. 89 A string 90} 91 92// for properties_test.go 93type tagTestProps struct { 94 A string `tag1:"a,b" tag2:"c"` 95 B string `tag1:"a,c"` 96 C string `tag1:"b,c"` 97 98 D struct { 99 E string `tag1:"a,b" tag2:"c"` 100 F string `tag1:"a,c"` 101 G string `tag1:"b,c"` 102 } `tag1:"b,c"` 103} 104 105var pkgPath string 106var pkgFiles map[string][]string 107var moduleTypeNameFactories map[string]reflect.Value 108var moduleTypeNamePropertyStructs map[string][]interface{} 109 110func init() { 111 pc, filename, _, _ := runtime.Caller(0) 112 fn := runtime.FuncForPC(pc) 113 114 var err error 115 pkgPath, err = funcNameToPkgPath(fn.Name()) 116 if err != nil { 117 panic(err) 118 } 119 120 pkgFiles = map[string][]string{ 121 pkgPath: {filename}, 122 } 123 124 factories := map[string]factoryFn{"foo": fooFactory, "bar": barFactory} 125 126 moduleTypeNameFactories = make(map[string]reflect.Value, len(factories)) 127 moduleTypeNamePropertyStructs = make(map[string][]interface{}, len(factories)) 128 for name, factory := range factories { 129 moduleTypeNameFactories[name] = reflect.ValueOf(factory) 130 _, structs := factory() 131 moduleTypeNamePropertyStructs[name] = structs 132 } 133} 134 135func TestModuleTypeDocs(t *testing.T) { 136 r := NewReader(pkgFiles) 137 for m := range moduleTypeNameFactories { 138 mt, err := r.ModuleType(m+"_module", moduleTypeNameFactories[m]) 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 expectedText := template.HTML(m + " docs.\n\n") 144 if mt.Text != expectedText { 145 t.Errorf("unexpected docs %q", mt.Text) 146 } 147 148 if mt.PkgPath != pkgPath { 149 t.Errorf("expected pkgpath %q, got %q", pkgPath, mt.PkgPath) 150 } 151 } 152} 153 154func TestPropertyStruct(t *testing.T) { 155 r := NewReader(pkgFiles) 156 ps, err := r.PropertyStruct(pkgPath, "props", reflect.ValueOf(props{A: "B"})) 157 if err != nil { 158 t.Fatal(err) 159 } 160 161 if ps.Text != "props docs.\n" { 162 t.Errorf("unexpected docs %q", ps.Text) 163 } 164 if len(ps.Properties) != 1 { 165 t.Fatalf("want 1 property, got %d", len(ps.Properties)) 166 } 167 168 if ps.Properties[0].Name != "a" || ps.Properties[0].Text != "A docs.\n\n" || ps.Properties[0].Default != "B" { 169 t.Errorf("unexpected property docs %q %q %q", 170 ps.Properties[0].Name, ps.Properties[0].Text, ps.Properties[0].Default) 171 } 172} 173 174func TestPackage(t *testing.T) { 175 r := NewReader(pkgFiles) 176 pkg, err := r.Package(pkgPath) 177 if err != nil { 178 t.Fatal(err) 179 } 180 181 if pkg.Text != "bpdoc docs.\n" { 182 t.Errorf("unexpected docs %q", pkg.Text) 183 } 184} 185 186func TestFuncToPkgPath(t *testing.T) { 187 tests := []struct { 188 f string 189 want string 190 }{ 191 { 192 f: "github.com/google/blueprint/bootstrap.Main", 193 want: "github.com/google/blueprint/bootstrap", 194 }, 195 { 196 f: "android/soong/android.GenruleFactory", 197 want: "android/soong/android", 198 }, 199 { 200 f: "android/soong/android.ModuleFactoryAdapter.func1", 201 want: "android/soong/android", 202 }, 203 { 204 f: "main.Main", 205 want: "main", 206 }, 207 } 208 for _, tt := range tests { 209 t.Run(tt.f, func(t *testing.T) { 210 got, err := funcNameToPkgPath(tt.f) 211 if err != nil { 212 t.Fatal(err) 213 } 214 if got != tt.want { 215 t.Errorf("funcNameToPkgPath(%v) = %v, want %v", tt.f, got, tt.want) 216 } 217 }) 218 } 219} 220