Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#247] Add .clangd configuration file syntax checker #249

Merged
merged 5 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class ClangdConfigFileChecker {
* @param configFile
*/
public void checkConfigFile(IFile configFile) {
if (!configFile.exists()) {
return;
}
Yaml yaml = new Yaml();
try (var inputStream = configFile.getContents()) {
jonahgraham marked this conversation as resolved.
Show resolved Hide resolved
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*******************************************************************************
* Copyright (c) 2024 Bachmann electronic GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Gesa Hentschke (Bachmann electronic GmbH) - initial implementation
*******************************************************************************/

package org.eclipse.cdt.lsp.internal.clangd.tests;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.eclipse.cdt.lsp.clangd.ClangdConfigurationFileManager;
import org.eclipse.cdt.lsp.clangd.tests.TestUtils;
import org.eclipse.cdt.lsp.internal.clangd.ClangdConfigFileChecker;
import org.eclipse.cdt.lsp.internal.clangd.ClangdConfigFileMonitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;

class ClangdConfigFileCheckerTest {
private static final String ERROR_MSG = ".clangd problem marker has not been added to the config file!";
private static final String VALID_YAML_SYNTAX = "\r\nCompileFlags: {CompilationDatabase: Release}\r\n";
private static final String INVALID_YAML_SYNTAX_TAB_ONLY = "\t";
private static final String INVALID_YAML_SYNTAX_CONTAINS_TAB = "\r\nCompileFlags:\n\tCompilationDatabase: Release";
private static final String INVALID_YAML_SYNTAX_MISSING_BRACE = "CompileFlags: {CompilationDatabase: Release\r\n";

private IProject project;

@BeforeEach
public void setUp(TestInfo testInfo) throws CoreException {
var projectName = TestUtils.getName(testInfo);
project = TestUtils.createCProject(projectName);
}

@AfterEach
public void cleanUp() throws CoreException {
TestUtils.deleteProject(project);
}

private IFile createConfigFile(String content) throws UnsupportedEncodingException, IOException, CoreException {
var file = project.getFile(ClangdConfigurationFileManager.CLANGD_CONFIG_FILE_NAME);
try (final var data = new ByteArrayInputStream(content.getBytes(project.getDefaultCharset()))) {
if (!file.exists()) {
file.create(data, false, new NullProgressMonitor());
} else {
file.setContents(data, IResource.KEEP_HISTORY, new NullProgressMonitor());
}
}
return file;
}

/**
* Test valid yaml syntax. No marker should be added.
*
* @throws IOException
* @throws CoreException
*/
@Test
void testValidYamlSyntax() throws IOException, CoreException {
// GIVEN an existing .clangd configuration file with valid yaml syntax:
var configFile = createConfigFile(VALID_YAML_SYNTAX);
// WHEN the ClangdConfigFileChecker().checkConfigFile get called on the configFile:
new ClangdConfigFileChecker().checkConfigFile(configFile);
// THEN we expect that NO ClangdConfigFileChecker.CLANGD_MARKER has been added:
var marker = configFile.findMarkers(ClangdConfigFileChecker.CLANGD_MARKER, false, IResource.DEPTH_ZERO);
assertNotNull(marker);
assertEquals(0, marker.length, "Expected no marker for valid yaml syntax");
}

/**
* Test whether a .clangd yaml Problem marker will be added to the .clangd file if the file contains invalid yaml syntax (here: tab only)
*
* @throws IOException
* @throws CoreException
*/
@Test
void testInvalidYamlSyntaxTabOnly() throws IOException, CoreException {
// GIVEN an existing .clangd configuration file with invalid yaml syntax (contains tab only):
var configFile = createConfigFile(INVALID_YAML_SYNTAX_TAB_ONLY);
// WHEN the ClangdConfigFileChecker().checkConfigFile get called on the configFile:
new ClangdConfigFileChecker().checkConfigFile(configFile);
// THEN we expect that an ClangdConfigFileChecker.CLANGD_MARKER has been added:
var marker = configFile.findMarkers(ClangdConfigFileChecker.CLANGD_MARKER, false, IResource.DEPTH_ZERO);
assertNotNull(marker);
assertEquals(1, marker.length, ERROR_MSG);
}

/**
* Test whether a .clangd yaml Problem marker will be added to the .clangd file if the file contains invalid yaml syntax (here: tab)
*
* @throws IOException
* @throws CoreException
*/
@Test
void testInvalidYamlSyntaxContainsTab() throws IOException, CoreException {
// GIVEN an existing .clangd configuration file with invalid yaml syntax (contains tab):
var configFile = createConfigFile(INVALID_YAML_SYNTAX_CONTAINS_TAB);
// WHEN the ClangdConfigFileChecker().checkConfigFile get called on the configFile:
new ClangdConfigFileChecker().checkConfigFile(configFile);
// THEN we expect that an ClangdConfigFileChecker.CLANGD_MARKER has been added:
var marker = configFile.findMarkers(ClangdConfigFileChecker.CLANGD_MARKER, false, IResource.DEPTH_ZERO);
assertNotNull(marker);
assertEquals(1, marker.length, ERROR_MSG);
}

/**
* Test whether a .clangd yaml Problem marker will be added to the .clangd file if the file contains invalid yaml syntax (here: missing closing brace)
* because the {@link ClangdConfigFileMonitor#checkJob} should have been run after a delay of 100ms.
*
* @throws IOException
* @throws CoreException
*/
@Test
void testInvalidYamlSyntaxMissingBrace() throws IOException, CoreException {
// GIVEN an existing .clangd configuration file with invalid yaml syntax (missing closing brace):
// WHEN a new .clang file gets added to the project (should trigger ClangdConfigFileMonitor.checkJob).
var configFile = createConfigFile(INVALID_YAML_SYNTAX_MISSING_BRACE);
// AND the UI thread sleeps for 1s:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is to test that the marker gets created? Instead can you test in a loop for the end condition so that the test doesn't wait longer than needed.

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// THEN we expect that an ClangdConfigFileChecker.CLANGD_MARKER has been added in the meantime,
// because the ClangdConfigFileMonitor.checkJob, which calls the ClangdConfigFileChecker().checkConfigFile, should have been run after a delay of 100ms:
var marker = configFile.findMarkers(ClangdConfigFileChecker.CLANGD_MARKER, false, IResource.DEPTH_ZERO);
assertNotNull(marker);
assertEquals(1, marker.length, ERROR_MSG);
}

}
Loading