blob: 286280984a44ac6c81f5be834088a5fcb9e62082 [file] [log] [blame]
/*
* Copyright (C) 2015 Square, 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.squareup.javapoet;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public final class CodeBlockTest {
@Test public void equalsAndHashCode() {
CodeBlock a = CodeBlock.builder().build();
CodeBlock b = CodeBlock.builder().build();
assertThat(a.equals(b)).isTrue();
assertThat(a.hashCode()).isEqualTo(b.hashCode());
a = CodeBlock.builder().add("$L", "taco").build();
b = CodeBlock.builder().add("$L", "taco").build();
assertThat(a.equals(b)).isTrue();
assertThat(a.hashCode()).isEqualTo(b.hashCode());
}
@Test public void of() {
CodeBlock a = CodeBlock.of("$L taco", "delicious");
assertThat(a.toString()).isEqualTo("delicious taco");
}
@Test public void isEmpty() {
assertTrue(CodeBlock.builder().isEmpty());
assertTrue(CodeBlock.builder().add("").isEmpty());
assertFalse(CodeBlock.builder().add(" ").isEmpty());
}
@Test public void indentCannotBeIndexed() {
try {
CodeBlock.builder().add("$1>", "taco").build();
fail();
} catch (IllegalArgumentException exp) {
assertThat(exp)
.hasMessageThat()
.isEqualTo("$$, $>, $<, $[, $], $W, and $Z may not have an index");
}
}
@Test public void deindentCannotBeIndexed() {
try {
CodeBlock.builder().add("$1<", "taco").build();
fail();
} catch (IllegalArgumentException exp) {
assertThat(exp)
.hasMessageThat()
.isEqualTo("$$, $>, $<, $[, $], $W, and $Z may not have an index");
}
}
@Test public void dollarSignEscapeCannotBeIndexed() {
try {
CodeBlock.builder().add("$1$", "taco").build();
fail();
} catch (IllegalArgumentException exp) {
assertThat(exp)
.hasMessageThat()
.isEqualTo("$$, $>, $<, $[, $], $W, and $Z may not have an index");
}
}
@Test public void statementBeginningCannotBeIndexed() {
try {
CodeBlock.builder().add("$1[", "taco").build();
fail();
} catch (IllegalArgumentException exp) {
assertThat(exp)
.hasMessageThat()
.isEqualTo("$$, $>, $<, $[, $], $W, and $Z may not have an index");
}
}
@Test public void statementEndingCannotBeIndexed() {
try {
CodeBlock.builder().add("$1]", "taco").build();
fail();
} catch (IllegalArgumentException exp) {
assertThat(exp)
.hasMessageThat()
.isEqualTo("$$, $>, $<, $[, $], $W, and $Z may not have an index");
}
}
@Test public void nameFormatCanBeIndexed() {
CodeBlock block = CodeBlock.builder().add("$1N", "taco").build();
assertThat(block.toString()).isEqualTo("taco");
}
@Test public void literalFormatCanBeIndexed() {
CodeBlock block = CodeBlock.builder().add("$1L", "taco").build();
assertThat(block.toString()).isEqualTo("taco");
}
@Test public void stringFormatCanBeIndexed() {
CodeBlock block = CodeBlock.builder().add("$1S", "taco").build();
assertThat(block.toString()).isEqualTo("\"taco\"");
}
@Test public void typeFormatCanBeIndexed() {
CodeBlock block = CodeBlock.builder().add("$1T", String.class).build();
assertThat(block.toString()).isEqualTo("java.lang.String");
}
@Test public void simpleNamedArgument() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("text", "taco");
CodeBlock block = CodeBlock.builder().addNamed("$text:S", map).build();
assertThat(block.toString()).isEqualTo("\"taco\"");
}
@Test public void repeatedNamedArgument() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("text", "tacos");
CodeBlock block = CodeBlock.builder()
.addNamed("\"I like \" + $text:S + \". Do you like \" + $text:S + \"?\"", map)
.build();
assertThat(block.toString()).isEqualTo(
"\"I like \" + \"tacos\" + \". Do you like \" + \"tacos\" + \"?\"");
}
@Test public void namedAndNoArgFormat() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("text", "tacos");
CodeBlock block = CodeBlock.builder()
.addNamed("$>\n$text:L for $$3.50", map).build();
assertThat(block.toString()).isEqualTo("\n tacos for $3.50");
}
@Test public void missingNamedArgument() {
try {
Map<String, Object> map = new LinkedHashMap<>();
CodeBlock.builder().addNamed("$text:S", map).build();
fail();
} catch(IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("Missing named argument for $text");
}
}
@Test public void lowerCaseNamed() {
try {
Map<String, Object> map = new LinkedHashMap<>();
map.put("Text", "tacos");
CodeBlock block = CodeBlock.builder().addNamed("$Text:S", map).build();
fail();
} catch(IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("argument 'Text' must start with a lowercase character");
}
}
@Test public void multipleNamedArguments() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("pipe", System.class);
map.put("text", "tacos");
CodeBlock block = CodeBlock.builder()
.addNamed("$pipe:T.out.println(\"Let's eat some $text:L\");", map)
.build();
assertThat(block.toString()).isEqualTo(
"java.lang.System.out.println(\"Let's eat some tacos\");");
}
@Test public void namedNewline() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("clazz", Integer.class);
CodeBlock block = CodeBlock.builder().addNamed("$clazz:T\n", map).build();
assertThat(block.toString()).isEqualTo("java.lang.Integer\n");
}
@Test public void danglingNamed() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("clazz", Integer.class);
try {
CodeBlock.builder().addNamed("$clazz:T$", map).build();
fail();
} catch(IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("dangling $ at end");
}
}
@Test public void indexTooHigh() {
try {
CodeBlock.builder().add("$2T", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("index 2 for '$2T' not in range (received 1 arguments)");
}
}
@Test public void indexIsZero() {
try {
CodeBlock.builder().add("$0T", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("index 0 for '$0T' not in range (received 1 arguments)");
}
}
@Test public void indexIsNegative() {
try {
CodeBlock.builder().add("$-1T", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("invalid format string: '$-1T'");
}
}
@Test public void indexWithoutFormatType() {
try {
CodeBlock.builder().add("$1", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("dangling format characters in '$1'");
}
}
@Test public void indexWithoutFormatTypeNotAtStringEnd() {
try {
CodeBlock.builder().add("$1 taco", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("invalid format string: '$1 taco'");
}
}
@Test public void indexButNoArguments() {
try {
CodeBlock.builder().add("$1T").build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("index 1 for '$1T' not in range (received 0 arguments)");
}
}
@Test public void formatIndicatorAlone() {
try {
CodeBlock.builder().add("$", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("dangling format characters in '$'");
}
}
@Test public void formatIndicatorWithoutIndexOrFormatType() {
try {
CodeBlock.builder().add("$ tacoString", String.class).build();
fail();
} catch (IllegalArgumentException expected) {
assertThat(expected).hasMessageThat().isEqualTo("invalid format string: '$ tacoString'");
}
}
@Test public void sameIndexCanBeUsedWithDifferentFormats() {
CodeBlock block = CodeBlock.builder()
.add("$1T.out.println($1S)", ClassName.get(System.class))
.build();
assertThat(block.toString()).isEqualTo("java.lang.System.out.println(\"java.lang.System\")");
}
@Test public void tooManyStatementEnters() {
CodeBlock codeBlock = CodeBlock.builder().add("$[$[").build();
try {
// We can't report this error until rendering type because code blocks might be composed.
codeBlock.toString();
fail();
} catch (IllegalStateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("statement enter $[ followed by statement enter $[");
}
}
@Test public void statementExitWithoutStatementEnter() {
CodeBlock codeBlock = CodeBlock.builder().add("$]").build();
try {
// We can't report this error until rendering type because code blocks might be composed.
codeBlock.toString();
fail();
} catch (IllegalStateException expected) {
assertThat(expected).hasMessageThat().isEqualTo("statement exit $] has no matching statement enter $[");
}
}
@Test public void join() {
List<CodeBlock> codeBlocks = new ArrayList<>();
codeBlocks.add(CodeBlock.of("$S", "hello"));
codeBlocks.add(CodeBlock.of("$T", ClassName.get("world", "World")));
codeBlocks.add(CodeBlock.of("need tacos"));
CodeBlock joined = CodeBlock.join(codeBlocks, " || ");
assertThat(joined.toString()).isEqualTo("\"hello\" || world.World || need tacos");
}
@Test public void joining() {
List<CodeBlock> codeBlocks = new ArrayList<>();
codeBlocks.add(CodeBlock.of("$S", "hello"));
codeBlocks.add(CodeBlock.of("$T", ClassName.get("world", "World")));
codeBlocks.add(CodeBlock.of("need tacos"));
CodeBlock joined = codeBlocks.stream().collect(CodeBlock.joining(" || "));
assertThat(joined.toString()).isEqualTo("\"hello\" || world.World || need tacos");
}
@Test public void joiningSingle() {
List<CodeBlock> codeBlocks = new ArrayList<>();
codeBlocks.add(CodeBlock.of("$S", "hello"));
CodeBlock joined = codeBlocks.stream().collect(CodeBlock.joining(" || "));
assertThat(joined.toString()).isEqualTo("\"hello\"");
}
@Test public void joiningWithPrefixAndSuffix() {
List<CodeBlock> codeBlocks = new ArrayList<>();
codeBlocks.add(CodeBlock.of("$S", "hello"));
codeBlocks.add(CodeBlock.of("$T", ClassName.get("world", "World")));
codeBlocks.add(CodeBlock.of("need tacos"));
CodeBlock joined = codeBlocks.stream().collect(CodeBlock.joining(" || ", "start {", "} end"));
assertThat(joined.toString()).isEqualTo("start {\"hello\" || world.World || need tacos} end");
}
}