package org.shedlang.compiler.config; import org.junit.jupiter.api.Test; import org.shedlang.compiler.config.errors.ConfigError; import org.shedlang.compiler.config.errors.Json5SyntaxConfigError; import org.shedlang.compiler.sources.SourceTexts; import org.shedlang.compiler.types.NamespaceName; import java.nio.file.Path; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; public class ProjectConfigTests { private static final Path PROJECT_PATH = Path.of("/projects/a"); @Test public void whenProjectConfigHasSyntaxErrorsOnFirstLineThenErrorIsThrown() { var error = assertThrows( Json5SyntaxConfigError.class, () -> parseProjectConfig("[1] ]1") ); assertThat(error.getMessage(), equalTo("Expected end of document, but was ']'")); assertThat(error.source().describe(), equalTo(""" :1:5 [1] ]1 ^""" )); } @Test public void whenProjectConfigHasSyntaxErrorsOnNonFirstLineThenErrorIsThrown() { var error = assertThrows( Json5SyntaxConfigError.class, () -> parseProjectConfig("[\n1\n]\n 2") ); assertThat(error.getMessage(), equalTo("Expected end of document, but was number '2'")); assertThat(error.source().describe(), equalTo(""" :4:3 2 ^""" )); } @Test public void canParseProjectConfigWithNoBins() { var config = parseProjectConfig("{}"); assertThat(config.bins(), isSequence()); } @Test public void canParseProjectConfigWithBins() { var config = parseProjectConfig(""" { bins: [ { name: "one", mainNamespace: "One", }, { name: "two", mainNamespace: "Two", }, ], } """); assertThat(config.bins(), isSequence( instanceOf( BinConfig.class, has("name", x -> x.name(), equalTo("one")), has("mainNamespace", x -> x.mainNamespace(), equalTo(NamespaceName.of("One"))) ), instanceOf( BinConfig.class, has("name", x -> x.name(), equalTo("two")), has("mainNamespace", x -> x.mainNamespace(), equalTo(NamespaceName.of("Two"))) ) )); } @Test public void whenProjectConfigHasBinsThatArentArrayThenErrorIsThrown() { var error = assertThrows( ConfigError.class, () -> parseProjectConfig(""" {bins: true}""" ) ); assertThat(error.getMessage(), equalTo("Expected $.bins to be array, but was boolean")); assertThat(error.source().describe(), equalTo(""" :1:8 {bins: true} ^^^^""" )); } @Test public void whenProjectConfigHasBinThatIsntObjectThenErrorIsThrown() { var error = assertThrows( ConfigError.class, () -> parseProjectConfig(""" { bins: [1], }""" ) ); assertThat(error.getMessage(), equalTo("Expected $.bins[0] to be object, but was finite number")); assertThat(error.source().describe(), equalTo(""" :2:12 bins: [1], ^""" )); } @Test public void canParseProjectConfigWithNoProfiles() { var config = parseProjectConfig("{}"); assertThat(config.profiles(), isSequence()); } @Test public void canParseProjectConfigWithProfiles() { var config = parseProjectConfig(""" { profiles: [ {name: "one"}, {name: "two"}, ], } """); assertThat(config.profiles(), isSequence( instanceOf( ProfileConfig.class, has("name", x -> x.name(), equalTo("one")) ), instanceOf( ProfileConfig.class, has("name", x -> x.name(), equalTo("two")) ) )); } @Test public void whenProjectConfigHasProfilesThatArentArrayThenErrorIsThrown() { var error = assertThrows( ConfigError.class, () -> parseProjectConfig(""" {profiles: true}""" ) ); assertThat(error.getMessage(), equalTo("Expected $.profiles to be array, but was boolean")); assertThat(error.source().describe(), equalTo(""" :1:12 {profiles: true} ^^^^""" )); } @Test public void whenProjectConfigHasProfileThatIsntObjectThenErrorIsThrown() { var error = assertThrows( ConfigError.class, () -> parseProjectConfig(""" { profiles: [1], }""" ) ); assertThat(error.getMessage(), equalTo("Expected $.profiles[0] to be object, but was finite number")); assertThat(error.source().describe(), equalTo(""" :2:16 profiles: [1], ^""" )); } private ProjectConfig parseProjectConfig(String text) { var sourceText = SourceTexts.string(text); return ProjectConfig.fromSourceText(PROJECT_PATH, sourceText); } }