/* * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.buck.config; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import com.facebook.buck.util.HumanReadableException; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.util.Optional; import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; public class ConfigTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void shouldGetBooleanValues() throws IOException { assertTrue( "a.b is true when 'yes'", ConfigBuilder.createFromText("[a]", " b = yes").getBooleanValue("a", "b", true)); assertTrue( "a.b is true when literally 'true'", ConfigBuilder.createFromText("[a]", " b = true").getBooleanValue("a", "b", true)); assertTrue( "a.b is true when 'YES' (capitalized)", ConfigBuilder.createFromText("[a]", " b = YES").getBooleanValue("a", "b", true)); assertFalse( "a.b is false by default", ConfigBuilder.createFromText("[x]", " y = COWS").getBooleanValue("a", "b", false)); assertFalse( "a.b is true when 'no'", ConfigBuilder.createFromText("[a]", " b = no").getBooleanValue("a", "b", true)); } @Test public void testGetFloat() throws IOException { assertEquals( Optional.of(0.333f), ConfigBuilder.createFromText("[a]", " f = 0.333").getFloat("a", "f")); } @Test public void testGetList() throws IOException { String[] config = {"[a]", " b = foo,bar,baz"}; ImmutableList.Builder<String> builder = ImmutableList.builder(); ImmutableList<String> expected = builder.add("foo").add("bar").add("baz").build(); assertEquals( expected, ConfigBuilder.createFromText(config[0], config[1]).getListWithoutComments("a", "b")); assertEquals( Optional.of(expected), ConfigBuilder.createFromText(config[0], config[1]) .getOptionalListWithoutComments("a", "b")); } @Test public void testGetListWithCustomSplitChar() throws IOException { String[] config = {"[a]", " b = cool;story;bro"}; ImmutableList.Builder<String> builder = ImmutableList.builder(); ImmutableList<String> expected = builder.add("cool").add("story").add("bro").build(); assertEquals( expected, ConfigBuilder.createFromText(config[0], config[1]).getListWithoutComments("a", "b", ';')); assertEquals( Optional.of(expected), ConfigBuilder.createFromText(config[0], config[1]) .getOptionalListWithoutComments("a", "b", ';')); } @Test public void testGetEmptyList() throws IOException { String[] config = {"[a]", "b ="}; assertThat( ConfigBuilder.createFromText(config[0], config[1]).getOptionalListWithoutComments("a", "b"), is(equalTo(Optional.of(ImmutableList.of())))); } @Test public void testGetEmptyListWithComment() throws IOException { String[] config = {"[a]", "b = ; comment"}; assertThat( ConfigBuilder.createFromText(config[0], config[1]).getOptionalListWithoutComments("a", "b"), is(equalTo(Optional.of(ImmutableList.of())))); } @Test public void testGetUnspecifiedList() throws IOException { String[] config = {"[a]", "c ="}; assertThat( ConfigBuilder.createFromText(config[0], config[1]).getOptionalListWithoutComments("a", "b"), is(equalTo(Optional.empty()))); } @Test(expected = HumanReadableException.class) public void testGetMalformedFloat() throws IOException { ConfigBuilder.createFromText("[a]", " f = potato").getFloat("a", "f"); } private enum TestEnum { A, B } @Test public void getEnum() { Config config = ConfigBuilder.createFromText("[section]", "field = A"); Optional<TestEnum> value = config.getEnum("section", "field", TestEnum.class); assertEquals(Optional.of(TestEnum.A), value); } @Test public void getEnumLowerCase() { Config config = ConfigBuilder.createFromText("[section]", "field = a"); Optional<TestEnum> value = config.getEnum("section", "field", TestEnum.class); assertEquals(Optional.of(TestEnum.A), value); } @Test(expected = HumanReadableException.class) public void getEnumInvalidValue() { Config config = ConfigBuilder.createFromText("[section]", "field = C"); config.getEnum("section", "field", TestEnum.class); } @Test public void getQuotedValue() throws IOException { assertEquals( "quoted strings are decoded", "foo [bar]\t\"\tbaz\\\n\u001f\udbcc\udc05\u6211\r", ConfigBuilder.createFromText( "[foo]", "bar=\"foo [bar]\\t\\\"\tbaz\\\\\\n\\x1f\\U00103005\\u6211\\r\"") .getValue("foo", "bar") .get()); } @Test public void getListWithQuotedParts() throws IOException { assertEquals( "lists with quoted parts are decoded", ImmutableList.of("foo bar", ",,,", ";", "\n"), ConfigBuilder.createFromText("[foo]", "bar=\"foo bar\" ,,, ; \"\\n\"") .getListWithoutComments("foo", "bar", ' ')); } @Test public void invalidEscapeSequence() throws IOException { String msg = ""; try { ConfigBuilder.createFromText("[foo]\nbar=\"\\z\"").getValue("foo", "bar"); } catch (HumanReadableException e) { msg = e.getMessage(); } assertEquals(".buckconfig: foo:bar: Invalid escape sequence: \\z", msg); } @Test public void invalidHexSequence() throws IOException { String msg = ""; try { ConfigBuilder.createFromText("[x]\ny=\"\\x4-\"").getValue("x", "y"); } catch (HumanReadableException e) { msg = e.getMessage(); } assertEquals(".buckconfig: x:y: Invalid hexadecimal digit in sequence: \\x4-", msg); } @Test public void missingCloseQuote() throws IOException { String msg = ""; try { ConfigBuilder.createFromText("[foo]\nbar=xyz\"asdfasdfasdf\n").getValue("foo", "bar"); } catch (HumanReadableException e) { msg = e.getMessage(); } assertEquals(".buckconfig: foo:bar: Input ends inside quoted string: \"asdfasdfa...", msg); } @Test public void shortHexSequence() throws IOException { String msg = ""; try { ConfigBuilder.createFromText("[foo]\nbar=\"\\u002").getValue("foo", "bar"); } catch (HumanReadableException e) { msg = e.getMessage(); } assertEquals(".buckconfig: foo:bar: Input ends inside hexadecimal sequence: \\u002", msg); } @Test public void configReference() { Config config = new Config( RawConfig.builder() .put("section", "field1", "hello $(config section.field2) world") .put("section", "field2", "goodbye") .build()); assertThat( config.get("section", "field1"), Matchers.equalTo(Optional.of("hello goodbye world"))); } @Test public void configReferenceAtStart() { Config config = new Config( RawConfig.builder() .put("section", "field1", "$(config section.field2) world") .put("section", "field2", "goodbye") .build()); assertThat(config.get("section", "field1"), Matchers.equalTo(Optional.of("goodbye world"))); } @Test public void escapedReference() { Config config = new Config( RawConfig.builder() .put("section", "field1", "hello \\$(config section.field2) world") .put("section", "field2", "goodbye") .build()); assertThat( config.get("section", "field1"), Matchers.equalTo(Optional.of("hello $(config section.field2) world"))); } @Test public void recursiveConfigReference() { Config config = new Config( RawConfig.builder() .put("section", "field1", "hello $(config section.field2) world") .put("section", "field2", "hello $(config section.field3) world") .put("section", "field3", "goodbye") .build()); assertThat( config.get("section", "field1"), Matchers.equalTo(Optional.of("hello hello goodbye world world"))); } @Test public void cyclicalConfigReference() { Config config = new Config( RawConfig.builder() .put("section", "field1", "$(config section.field2)") .put("section", "field2", "$(config section.field3)") .put("section", "field3", "$(config section.field1)") .build()); expectedException.expect(HumanReadableException.class); expectedException.expectMessage( "section.field1 -> section.field2 -> section.field3 -> section.field1"); config.get("section", "field1"); } @Test public void locationMacroIsPreserved() { Config config = new Config( RawConfig.builder().put("section", "field", "hello $(location input) world").build()); assertThat( config.get("section", "field"), Matchers.equalTo(Optional.of("hello $(location input) world"))); } @Test public void equalsIgnoringIgnoresValueOfSingleField() { assertThat( new Config(RawConfig.builder().put("section", "field", "valueLeft").build()) .equalsIgnoring( new Config(RawConfig.builder().put("section", "field", "valueRight").build()), ImmutableMap.of("section", ImmutableSet.of("field"))), is(true)); assertThat( new Config( RawConfig.builder() .put("section", "field", "valueLeft") .put("section", "field_b", "value") .build()) .equalsIgnoring( new Config( RawConfig.builder() .put("section", "field", "valueRight") .put("section", "field_b", "value") .build()), ImmutableMap.of("section", ImmutableSet.of("field"))), is(true)); } @Test public void equalsIgnoringIgnoresPresenceOfIgnoredField() { assertThat( new Config(RawConfig.builder().put("section", "field", "value").build()) .equalsIgnoring( new Config(RawConfig.builder().build()), ImmutableMap.of("section", ImmutableSet.of("field"))), is(true)); assertThat( new Config( RawConfig.builder() .put("section", "field", "value") .put("section", "field_b", "value") .build()) .equalsIgnoring( new Config(RawConfig.builder().put("section", "field_b", "value").build()), ImmutableMap.of("section", ImmutableSet.of("field"))), is(true)); assertThat( new Config( RawConfig.builder() .put("section", "field", "value") .put("section_b", "field_b", "value") .build()) .equalsIgnoring( new Config(RawConfig.builder().put("section_b", "field_b", "value").build()), ImmutableMap.of("section", ImmutableSet.of("field"))), is(true)); } }