blob: 54aa71b2946bea5786c5866e302d99f5f1a30b22 [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 main
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"go.fuchsia.dev/fuchsia/tools/staticanalysis"
)
type file struct {
path string
content string
}
func TestAnalyzer(t *testing.T) {
areasFile := file{
path: "docs/contribute/governance/rfcs/_areas.yaml",
content: `
- Bluetooth
- Kernel
`,
}
tests := []struct {
name string
path string
files []file
expected []*staticanalysis.Finding
}{
{
name: "toc won't parse",
path: "docs/contribute/governance/rfcs/_toc.yaml",
files: []file{{
path: "docs/contribute/governance/rfcs/_toc.yaml",
content: "asd'f",
}},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/toc/failed_to_parse",
Message: "Failed to parse yaml: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `asd'f` into main.toc",
Path: "docs/contribute/governance/rfcs/_toc.yaml",
},
},
},
{
name: "rfc index won't parse",
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
files: []file{{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: "asd'f",
}},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/index/failed_to_parse",
Message: "Failed to parse yaml: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `asd'f` into []*main.rfcIndexEntry",
Path: "docs/contribute/governance/rfcs/_rfcs.yaml",
},
},
},
{
name: "rfc index won't parse, rfc file still works",
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
files: []file{
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: "asd'f",
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `
<!-- mdformat off(templates not supported) -->
{% set rfcid = "RFC-1234" %}
`,
},
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/file/not_in_toc",
Message: "No matching entry in _toc.yaml",
Path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
},
{
Category: "rfcmeta/file/not_in_index",
Message: "RFC is not listed in _rfcs.yaml",
Path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
},
},
},
{
name: "toc path mismatch",
path: "docs/contribute/governance/rfcs/_toc.yaml",
files: []file{
{
path: "docs/contribute/governance/rfcs/_toc.yaml",
content: `
toc:
- title: "RFC-1234"
path: "docs/contribute/governance/rfcs/0001_rfc_process.md"
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `
<!-- mdformat off(templates not supported) -->
{% set rfcid = "RFC-1234" %}
`,
},
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/toc/unexpected_path",
Message: `path for "RFC-1234" should begin with "/docs/contribute/governance/rfcs/1234_"; found "docs/contribute/governance/rfcs/0001_rfc_process.md"`,
Path: "docs/contribute/governance/rfcs/_toc.yaml",
Line: 3,
EndLine: 3,
},
{
Category: "rfcmeta/toc/file_not_found",
Message: `File "docs/contribute/governance/rfcs/0001_rfc_process.md" doesn't exist`,
Path: "docs/contribute/governance/rfcs/_toc.yaml",
Line: 3,
EndLine: 3,
},
},
},
{
name: "rfc in toc and index",
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
files: []file{
{
path: "docs/contribute/governance/rfcs/_toc.yaml",
content: `
toc:
- title: "RFCs"
section:
- title: "RFC-1234"
path: "/docs/contribute/governance/rfcs/1234_my_rfc.md"
`,
},
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: `
- name: 'RFC-1234'
title: 'My RFC'
short_description: "This RFC is mine. You can't have it."
authors: ['page@google.com']
file: '1234_my_rfc.md'
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `{% set rfcid = "RFC-1234" %}`,
},
},
expected: nil,
},
{
name: "rfcid tag missing ",
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
files: []file{
{
path: "docs/contribute/governance/rfcs/_toc.yaml",
content: `
toc:
- title: "RFCs"
section:
- title: "RFC-1234"
path: "/docs/contribute/governance/rfcs/1234_my_rfc.md"
`,
},
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: `
- name: 'RFC-1234'
title: 'My RFC'
short_description: "This RFC is mine. You can't have it."
authors: ['page@google.com']
file: '1234_my_rfc.md'
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: ``,
},
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/file/rfcid_tag_not_found",
Message: "No `{% set rfcid = \"RFC-1234\" %}` tag found.",
Path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
},
},
},
{
name: "missing area",
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
files: []file{
areasFile,
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: `
- name: 'RFC-1234'
title: 'My RFC'
short_description: "This RFC is mine. You can't have it."
authors: ['page@google.com']
file: '1234_my_rfc.md'
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `{% set rfcid = "RFC-1234" %}`,
},
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/index/missing_area",
Message: `Include an 'area' for this RFC. Options are listed in //docs/contribute/governance/rfcs/_areas.yaml`,
Path: "docs/contribute/governance/rfcs/_rfcs.yaml",
Line: 2,
EndLine: 2,
},
},
},
{
name: "known area",
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
files: []file{
areasFile,
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: `
- name: 'RFC-1234'
title: 'My RFC'
short_description: "This RFC is mine. You can't have it."
authors: ['page@google.com']
file: '1234_my_rfc.md'
area: ['Kernel']
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `{% set rfcid = "RFC-1234" %}`,
},
},
expected: nil,
},
{
name: "areas file malformed",
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
files: []file{
{
path: "docs/contribute/governance/rfcs/_areas.yaml",
content: `asd'f`,
},
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: `
- name: 'RFC-1234'
title: 'My RFC'
short_description: "This RFC is mine. You can't have it."
authors: ['page@google.com']
file: '1234_my_rfc.md'
area: ['Kernel']
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `{% set rfcid = "RFC-1234" %}`,
},
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/index/unknown_area",
Message: `area "Kernel" is not listed in //docs/contribute/governance/rfcs/_areas.yaml`,
Path: "docs/contribute/governance/rfcs/_rfcs.yaml",
Line: 2,
EndLine: 2,
},
},
},
{
name: "unknown area",
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
files: []file{
areasFile,
{
path: "docs/contribute/governance/rfcs/_rfcs.yaml",
content: `
- name: 'RFC-1234'
title: 'My RFC'
short_description: "This RFC is mine. You can't have it."
authors: ['page@google.com']
file: '1234_my_rfc.md'
area: ['Kernel', 'Area 51']
`,
},
{
path: "docs/contribute/governance/rfcs/1234_my_rfc.md",
content: `{% set rfcid = "RFC-1234" %}`,
},
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/index/unknown_area",
Message: `area "Area 51" is not listed in //docs/contribute/governance/rfcs/_areas.yaml`,
Path: "docs/contribute/governance/rfcs/_rfcs.yaml",
Line: 2,
EndLine: 2,
},
},
},
{
name: "placeholder filename",
path: "docs/contribute/governance/rfcs/NNNN_unfinished_rfc.md",
files: []file{
{
path: "docs/contribute/governance/rfcs/NNNN_unfinished_rfc.md",
content: `{% set rfcid = "RFC-NNNN" %}`,
},
areasFile,
},
expected: []*staticanalysis.Finding{
{
Category: "rfcmeta/file/placeholder_id",
Message: `RFC filename begins with "NNNN". Replace it with the RFC number before submitting.`,
Path: "docs/contribute/governance/rfcs/NNNN_unfinished_rfc.md",
},
{
Category: "rfcmeta/file/not_in_toc",
Message: "No matching entry in _toc.yaml",
Path: "docs/contribute/governance/rfcs/NNNN_unfinished_rfc.md",
},
{
Category: "rfcmeta/file/not_in_index",
Message: "RFC is not listed in _rfcs.yaml",
Path: "docs/contribute/governance/rfcs/NNNN_unfinished_rfc.md",
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
checkoutDir := t.TempDir()
if err := os.MkdirAll(filepath.Join(checkoutDir, "docs/contribute/governance/rfcs"), 0o700); err != nil {
t.Fatal(err)
}
analyzer := analyzer{checkoutDir: checkoutDir}
for _, file := range test.files {
if err := os.WriteFile(filepath.Join(checkoutDir, file.path), []byte(file.content), 0o600); err != nil {
t.Fatal(err)
}
}
findings, err := analyzer.Analyze(context.Background(), test.path)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(test.expected, findings, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("Analyzer diff (-want +got):\n%s", diff)
}
})
}
}