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 "github.com/google/blueprint/proptools" 26) 27 28type factoryFn func() (blueprint.Module, []interface{}) 29 30// foo docs. 31func fooFactory() (blueprint.Module, []interface{}) { 32 return nil, []interface{}{&props{}} 33} 34 35// bar docs. 36func barFactory() (blueprint.Module, []interface{}) { 37 return nil, []interface{}{&complexProps{}} 38} 39 40type structToNest struct { 41 E string 42} 43 44type StructToEmbed struct { 45 Nested_in_embedded structToNest 46 47 // F string 48 F string 49} 50 51type otherStructToNest struct { 52 G string 53} 54 55type OtherStructToEmbed struct { 56 Nested_in_other_embedded otherStructToNest 57 58 // F string 59 H string 60} 61 62type StructWithEmbedded struct { 63 StructToEmbed 64} 65 66// for bpdoc_test.go 67type complexProps struct { 68 A string 69 B_mutated string `blueprint:"mutated"` 70 71 Nested struct { 72 C string 73 D_mutated string `blueprint:"mutated"` 74 } 75 76 Nested_struct structToNest 77 78 Struct_has_embed StructWithEmbedded 79 80 OtherStructToEmbed 81 82 List_of_ints []int 83 84 List_of_nested []structToNest 85 86 Configurable_bool proptools.Configurable[bool] 87} 88 89// props docs. 90type props struct { 91 // A docs. 92 A string 93} 94 95// for properties_test.go 96type tagTestProps struct { 97 A string `tag1:"a,b" tag2:"c"` 98 B string `tag1:"a,c"` 99 C string `tag1:"b,c"` 100 101 D struct { 102 E string `tag1:"a,b" tag2:"c"` 103 F string `tag1:"a,c"` 104 G string `tag1:"b,c"` 105 } `tag1:"b,c"` 106} 107 108var pkgPath string 109var pkgFiles map[string][]string 110var moduleTypeNameFactories map[string]reflect.Value 111var moduleTypeNamePropertyStructs map[string][]interface{} 112 113func init() { 114 pc, filename, _, _ := runtime.Caller(0) 115 fn := runtime.FuncForPC(pc) 116 117 var err error 118 pkgPath, err = funcNameToPkgPath(fn.Name()) 119 if err != nil { 120 panic(err) 121 } 122 123 pkgFiles = map[string][]string{ 124 pkgPath: {filename}, 125 } 126 127 factories := map[string]factoryFn{"foo": fooFactory, "bar": barFactory} 128 129 moduleTypeNameFactories = make(map[string]reflect.Value, len(factories)) 130 moduleTypeNamePropertyStructs = make(map[string][]interface{}, len(factories)) 131 for name, factory := range factories { 132 moduleTypeNameFactories[name] = reflect.ValueOf(factory) 133 _, structs := factory() 134 moduleTypeNamePropertyStructs[name] = structs 135 } 136} 137 138func TestModuleTypeDocs(t *testing.T) { 139 r := NewReader(pkgFiles) 140 for m := range moduleTypeNameFactories { 141 mt, err := r.ModuleType(m+"_module", moduleTypeNameFactories[m]) 142 if err != nil { 143 t.Fatal(err) 144 } 145 146 expectedText := template.HTML(m + " docs.\n\n") 147 if mt.Text != expectedText { 148 t.Errorf("unexpected docs %q", mt.Text) 149 } 150 151 if mt.PkgPath != pkgPath { 152 t.Errorf("expected pkgpath %q, got %q", pkgPath, mt.PkgPath) 153 } 154 } 155} 156 157func TestPropertyStruct(t *testing.T) { 158 r := NewReader(pkgFiles) 159 ps, err := r.PropertyStruct(pkgPath, "props", reflect.ValueOf(props{A: "B"})) 160 if err != nil { 161 t.Fatal(err) 162 } 163 164 if ps.Text != "props docs.\n" { 165 t.Errorf("unexpected docs %q", ps.Text) 166 } 167 if len(ps.Properties) != 1 { 168 t.Fatalf("want 1 property, got %d", len(ps.Properties)) 169 } 170 171 if ps.Properties[0].Name != "a" || ps.Properties[0].Text != "A docs.\n\n" || ps.Properties[0].Default != "B" { 172 t.Errorf("unexpected property docs %q %q %q", 173 ps.Properties[0].Name, ps.Properties[0].Text, ps.Properties[0].Default) 174 } 175} 176 177func TestPackage(t *testing.T) { 178 r := NewReader(pkgFiles) 179 pkg, err := r.Package(pkgPath) 180 if err != nil { 181 t.Fatal(err) 182 } 183 184 if pkg.Text != "bpdoc docs.\n" { 185 t.Errorf("unexpected docs %q", pkg.Text) 186 } 187} 188 189func TestFuncToPkgPath(t *testing.T) { 190 tests := []struct { 191 f string 192 want string 193 }{ 194 { 195 f: "github.com/google/blueprint/bootstrap.Main", 196 want: "github.com/google/blueprint/bootstrap", 197 }, 198 { 199 f: "android/soong/android.GenruleFactory", 200 want: "android/soong/android", 201 }, 202 { 203 f: "android/soong/android.ModuleFactoryAdapter.func1", 204 want: "android/soong/android", 205 }, 206 { 207 f: "main.Main", 208 want: "main", 209 }, 210 } 211 for _, tt := range tests { 212 t.Run(tt.f, func(t *testing.T) { 213 got, err := funcNameToPkgPath(tt.f) 214 if err != nil { 215 t.Fatal(err) 216 } 217 if got != tt.want { 218 t.Errorf("funcNameToPkgPath(%v) = %v, want %v", tt.f, got, tt.want) 219 } 220 }) 221 } 222} 223