| // Copyright 2019 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // bpdoc docs. |
| package bpdoc |
| |
| import ( |
| "html/template" |
| "reflect" |
| "runtime" |
| "testing" |
| |
| "github.com/google/blueprint" |
| ) |
| |
| type factoryFn func() (blueprint.Module, []interface{}) |
| |
| // foo docs. |
| func fooFactory() (blueprint.Module, []interface{}) { |
| return nil, []interface{}{&props{}} |
| } |
| |
| // bar docs. |
| func barFactory() (blueprint.Module, []interface{}) { |
| return nil, []interface{}{&complexProps{}} |
| } |
| |
| type structToNest struct { |
| E string |
| } |
| |
| type StructToEmbed struct { |
| Nested_in_embedded structToNest |
| |
| // F string |
| F string |
| } |
| |
| type otherStructToNest struct { |
| G string |
| } |
| |
| type OtherStructToEmbed struct { |
| Nested_in_other_embedded otherStructToNest |
| |
| // F string |
| H string |
| } |
| |
| type StructWithEmbedded struct { |
| StructToEmbed |
| } |
| |
| // for bpdoc_test.go |
| type complexProps struct { |
| A string |
| B_mutated string `blueprint:"mutated"` |
| |
| Nested struct { |
| C string |
| D_mutated string `blueprint:"mutated"` |
| } |
| |
| Nested_struct structToNest |
| |
| Struct_has_embed StructWithEmbedded |
| |
| OtherStructToEmbed |
| |
| List_of_ints []int |
| |
| List_of_nested []structToNest |
| } |
| |
| // props docs. |
| type props struct { |
| // A docs. |
| A string |
| } |
| |
| // for properties_test.go |
| type tagTestProps struct { |
| A string `tag1:"a,b" tag2:"c"` |
| B string `tag1:"a,c"` |
| C string `tag1:"b,c"` |
| |
| D struct { |
| E string `tag1:"a,b" tag2:"c"` |
| F string `tag1:"a,c"` |
| G string `tag1:"b,c"` |
| } `tag1:"b,c"` |
| } |
| |
| var pkgPath string |
| var pkgFiles map[string][]string |
| var moduleTypeNameFactories map[string]reflect.Value |
| var moduleTypeNamePropertyStructs map[string][]interface{} |
| |
| func init() { |
| pc, filename, _, _ := runtime.Caller(0) |
| fn := runtime.FuncForPC(pc) |
| |
| var err error |
| pkgPath, err = funcNameToPkgPath(fn.Name()) |
| if err != nil { |
| panic(err) |
| } |
| |
| pkgFiles = map[string][]string{ |
| pkgPath: {filename}, |
| } |
| |
| factories := map[string]factoryFn{"foo": fooFactory, "bar": barFactory} |
| |
| moduleTypeNameFactories = make(map[string]reflect.Value, len(factories)) |
| moduleTypeNamePropertyStructs = make(map[string][]interface{}, len(factories)) |
| for name, factory := range factories { |
| moduleTypeNameFactories[name] = reflect.ValueOf(factory) |
| _, structs := factory() |
| moduleTypeNamePropertyStructs[name] = structs |
| } |
| } |
| |
| func TestModuleTypeDocs(t *testing.T) { |
| r := NewReader(pkgFiles) |
| for m := range moduleTypeNameFactories { |
| mt, err := r.ModuleType(m+"_module", moduleTypeNameFactories[m]) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| expectedText := template.HTML(m + " docs.\n\n") |
| if mt.Text != expectedText { |
| t.Errorf("unexpected docs %q", mt.Text) |
| } |
| |
| if mt.PkgPath != pkgPath { |
| t.Errorf("expected pkgpath %q, got %q", pkgPath, mt.PkgPath) |
| } |
| } |
| } |
| |
| func TestPropertyStruct(t *testing.T) { |
| r := NewReader(pkgFiles) |
| ps, err := r.PropertyStruct(pkgPath, "props", reflect.ValueOf(props{A: "B"})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| if ps.Text != "props docs.\n" { |
| t.Errorf("unexpected docs %q", ps.Text) |
| } |
| if len(ps.Properties) != 1 { |
| t.Fatalf("want 1 property, got %d", len(ps.Properties)) |
| } |
| |
| if ps.Properties[0].Name != "a" || ps.Properties[0].Text != "A docs.\n\n" || ps.Properties[0].Default != "B" { |
| t.Errorf("unexpected property docs %q %q %q", |
| ps.Properties[0].Name, ps.Properties[0].Text, ps.Properties[0].Default) |
| } |
| } |
| |
| func TestPackage(t *testing.T) { |
| r := NewReader(pkgFiles) |
| pkg, err := r.Package(pkgPath) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| if pkg.Text != "bpdoc docs.\n" { |
| t.Errorf("unexpected docs %q", pkg.Text) |
| } |
| } |
| |
| func TestFuncToPkgPath(t *testing.T) { |
| tests := []struct { |
| f string |
| want string |
| }{ |
| { |
| f: "github.com/google/blueprint/bootstrap.Main", |
| want: "github.com/google/blueprint/bootstrap", |
| }, |
| { |
| f: "android/soong/android.GenruleFactory", |
| want: "android/soong/android", |
| }, |
| { |
| f: "android/soong/android.ModuleFactoryAdapter.func1", |
| want: "android/soong/android", |
| }, |
| { |
| f: "main.Main", |
| want: "main", |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.f, func(t *testing.T) { |
| got, err := funcNameToPkgPath(tt.f) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if got != tt.want { |
| t.Errorf("funcNameToPkgPath(%v) = %v, want %v", tt.f, got, tt.want) |
| } |
| }) |
| } |
| } |