// Copyright 2020 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 langserver

import (
	"testing"

	"github.com/sourcegraph/go-lsp"
)

func TestFileWithNoDiagnostics(t *testing.T) {
	handler := NewHandlerWithFiles(TestFile{
		Name: "test.fidl",
		Text: `// Copyright 2020 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.

library test;
const uint8 VALID_NAME = 1;

struct Foo {
	uint8 field_name;
};

protocol Bar {
	Baz(string:256 message);
};
`,
	})

	diags, err := handler.getDiagnosticsForLibraryWithFile(lsp.DocumentURI("test.fidl"))
	if err != nil {
		t.Fatalf("failed to publish diagnostics: %s", err)
	}
	if len(diags["test.fidl"]) > 0 {
		t.Fatalf("incorrect number of diagnostics; expected 0, actual %d", len(diags))
	}
}

func TestDiagnosticsFidlcErrors(t *testing.T) {
	handler := NewHandlerWithFiles(TestFile{
		Name: "test.fidl",
		Text: `// Copyright 2020 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.

library test;
const uint8 DUPLICATE_NAME = 0;
const uint8 DUPLICATE_NAME = 1;
//          ~~~~~~~~~~~~~~ expected range of diagnostic
`,
	})

	allDiags, err := handler.getDiagnosticsForLibraryWithFile(lsp.DocumentURI("test.fidl"))
	if err != nil {
		t.Fatalf("failed to publish diagnostics: %s", err)
	}
	diags := allDiags["test.fidl"]
	if len(diags) != 1 {
		t.Fatalf("incorrect number of diagnostics %d; expected 1", len(diags))
	}
	if diags[0].Source != "fidlc" {
		t.Errorf("unexpected source of diagnostic %s; expected `fidlc`", diags[0].Source)
	}
	expRange := lsp.Range{
		Start: lsp.Position{Line: 6, Character: 12},
		End:   lsp.Position{Line: 6, Character: 26},
	}
	if diags[0].Range != expRange {
		t.Errorf("unexpected range of diagnostic %v; expected %v", diags[0].Range, expRange)
	}
	if diags[0].Severity != lsp.Error {
		t.Errorf("unexpected severity of diagnostic %v; expected %v", diags[0].Severity, lsp.Error)
	}
}

func TestDiagnosticsFidlcWarnings(t *testing.T) {
	handler := NewHandlerWithFiles(TestFile{
		Name: "test.fidl",
		Text: `// Copyright 2020 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.

library test;

[layout = "Simple"]
//~~~~~~~~~~~~~~~~ expected range of diagnostic
struct S {
	uint8 foo;
};
`,
	})

	allDiags, err := handler.getDiagnosticsForLibraryWithFile(lsp.DocumentURI("test.fidl"))
	if err != nil {
		t.Fatalf("failed to publish diagnostics: %s", err)
	}
	diags := allDiags["test.fidl"]
	if len(diags) != 1 {
		t.Fatalf("incorrect number of diagnostics %d; expected 1", len(diags))
	}
	if diags[0].Source != "fidlc" {
		t.Errorf("unexpected source of diagnostic %s; expected `fidlc`", diags[0].Source)
	}
	expRange := lsp.Range{
		Start: lsp.Position{Line: 6, Character: 1},
		End:   lsp.Position{Line: 6, Character: 18},
	}
	if diags[0].Range != expRange {
		t.Errorf("unexpected range of diagnostic %v; expected %v", diags[0].Range, expRange)
	}
	if diags[0].Severity != lsp.Warning {
		t.Errorf("unexpected severity of diagnostic %v; expected %v", diags[0].Severity, lsp.Warning)
	}
}

func TestDiagnosticsFidlLint(t *testing.T) {
	handler := NewHandlerWithFiles(TestFile{
		Name: "test.fidl",
		Text: `
library x;

enum my_enum {
    IncorrectCamelCase = 1;
};
`,
	})

	allDiags, err := handler.getDiagnosticsForLibraryWithFile(lsp.DocumentURI("test.fidl"))
	if err != nil {
		t.Fatalf("failed to publish diagnostics: %s", err)
	}
	diags := allDiags["test.fidl"]
	if len(diags) != 4 {
		t.Fatalf("incorrect number of diagnostics %d; expected 4", len(diags))
	}
	for _, diag := range diags {
		if diag.Source != "fidl-lint" {
			t.Errorf("unexpected source of diagnostic %s; expected `fidl-lint`", diag.Source)
		}
		if diag.Severity != lsp.Warning {
			t.Errorf("unexpected severity of diagnostic %v; expected %v", diag.Severity, lsp.Warning)
		}
	}
}

func TestErrorAndLint(t *testing.T) {
	handler := NewHandlerWithFiles(TestFile{
		Name: "test.fidl",
		Text: `
// expected lint: need Fuchsia copyright notice
library test;

protocol P {
	DuplicateMethodName();
	DuplicateMethodName();
// expected error: duplicate method name
};
`,
	})

	diags, err := handler.getDiagnosticsForLibraryWithFile(lsp.DocumentURI("test.fidl"))
	if err != nil {
		t.Fatalf("failed to publish diagnostics: %s", err)
	}
	if len(diags["test.fidl"]) != 2 {
		t.Fatalf("incorrect number of diagnostics %d; expected 3", len(diags["test.fidl"]))
	}
}
