blob: 87d6f152bf1ac34f3905cd614b21514d07051718 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package docgen
import (
"go.fuchsia.dev/fuchsia/tools/cppdocgen/clangdoc"
"reflect"
"testing"
)
// This makes some assumptions about the format of the comment hierarchy that is allowed to change
// over time (there may be "paragraph" comments as a middle hierarchy, for example).
func assertDocstringIs(t *testing.T, actual []clangdoc.CommentInfo, expected []string) {
if len(expected) == 0 {
if len(actual) > 0 {
t.Errorf("Expecting empty docstring.")
}
return
}
// Outer one is always the full comment.
if len(actual) != 1 {
t.Errorf("Expecting a single comment, got %d", len(actual))
return
}
if actual[0].Kind != "FullComment" {
t.Errorf("Expecting a full comment, got '%s'", actual[0].Kind)
return
}
children := actual[0].Children
if len(children) != len(expected) {
t.Errorf("Expecting %d lines of header docstring, got %d\n",
len(expected), len(children))
return
}
for i := 0; i < len(expected); i++ {
if children[i].Kind != "TextComment" {
t.Errorf("Expecting 'TextComment', got '%s'\n", children[i].Kind)
}
if children[i].Text != expected[i] {
t.Errorf("Expecting for line %d of docstring:\n '%s'\nGot:\n '%s'\n",
i, expected[i], children[i].Text)
}
}
}
func assertDefinesAre(t *testing.T, actual []*Define, expected []*Define) {
if !reflect.DeepEqual(actual, expected) {
t.Errorf("For defines, expected\n %v\nGot\n %v\n", expected, actual)
return
}
}
// This also tests line classifications.
func TestParseHeaderWithHeaderDocstring(t *testing.T) {
contents := `// Copyright blah blah
// Second line of copyright
#ifdef FOO
#define FOO
/// This is the header docstring.
///
/// It is nice
// Not the header docstring, random thing to delete.
// Fromulator max description.
//
// Woot
#define FROMULATOR_MAX 512
/// Complicated multiline define.
#define FROMULATOR_GET_MIN(a, b) {\
DoTheThing(a, b) \
}
int GetThing();
#endif
`
vals := ParseHeader(contents, "filename.h")
assertDocstringIs(t, vals.Description, []string{
" This is the header docstring.",
"",
" It is nice",
})
expectedDefines := []*Define{
{Location: clangdoc.Location{LineNumber: 16, Filename: "filename.h"},
Name: "FROMULATOR_MAX",
ParamString: "",
Value: "512",
Description: commentsToDescription([]string{" Fromulator max description.", "", " Woot"}),
},
{Location: clangdoc.Location{LineNumber: 19, Filename: "filename.h"},
Name: "FROMULATOR_GET_MIN",
ParamString: "(a, b)",
Value: "{\\",
Description: commentsToDescription([]string{" Complicated multiline define."}),
},
}
assertDefinesAre(t, vals.Defines, expectedDefines)
// Corresponds to the classification of each line in the code block above.
expectedClasses := [...]LineClass{
LineClassComment,
LineClassComment,
LineClassBlank,
LineClassPreproc,
LineClassPreproc,
LineClassBlank,
LineClassComment,
LineClassComment,
LineClassComment,
LineClassBlank,
LineClassComment,
LineClassBlank,
LineClassComment,
LineClassComment,
LineClassComment,
LineClassPreproc,
LineClassBlank,
LineClassComment,
LineClassPreproc,
LineClassCode, // This should be preproc but we don't handle multiline defines yet.
LineClassCode, // This should be preproc but we don't handle multiline defines yet.
LineClassBlank,
LineClassCode,
LineClassBlank,
LineClassPreproc,
LineClassBlank}
if len(expectedClasses) != len(vals.Classes) {
t.Errorf("Expecting %d lines of header line classes, got %d\n",
len(expectedClasses), len(vals.Classes))
}
for i := range expectedClasses {
if expectedClasses[i] != vals.Classes[i] {
t.Errorf("Expected line index %d to be class %d, got %d\n",
i, expectedClasses[i], vals.Classes[i])
}
}
}
func TestParseHeaderWithNonDocstring(t *testing.T) {
contents := `// Copyright blah blah
// Second line of copyright
#ifdef FOO
#define FOO
/// Not the header docstring
int SomeFunc();
/// This is not the header docstring either.
///
/// It is nice
`
vals := ParseHeader(contents, "filename.h")
if len(vals.Description) != 0 {
t.Errorf("Expected no docstring.")
}
}
func TestParseHeaderDefines(t *testing.T) {
contents := `// Copyright blah blah
// Second line of copyright
#define FOO
#define LAZ a
/// Some docs
///
/// For the define
#define BAR (a)
// Currently this just gets the params from the first line.
# define TAZ( a, b ) \
blah
// This define should be skipped because of: $nodoc
#define THE_ONE_THAT_SHOULD_NOT_BE_DOCUMENTED true
`
vals := ParseHeader(contents, "filename.h")
expectedDefines := []*Define{
// Note that "FOO" is not listed because it has no value.
{Location: clangdoc.Location{LineNumber: 6, Filename: "filename.h"},
Name: "LAZ",
ParamString: "",
Value: "a",
},
{Location: clangdoc.Location{LineNumber: 11, Filename: "filename.h"},
Name: "BAR",
ParamString: "",
Value: "(a)",
Description: commentsToDescription([]string{" Some docs", "", " For the define"}),
},
{Location: clangdoc.Location{LineNumber: 14, Filename: "filename.h"},
Name: "TAZ",
ParamString: "( a, b )",
Value: "\\",
Description: commentsToDescription([]string{" Currently this just gets the params from the first line."}),
},
}
assertDefinesAre(t, vals.Defines, expectedDefines)
}