Git Product home page Git Product logo

compile-testing's Introduction

Compile Testing

Build Status Maven Release Javadoc

A library for testing javac compilation with or without annotation processors. See the javadoc for usage examples.

License

Copyright 2013 Google, 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.

compile-testing's People

Contributors

brycecicada avatar cgdecker avatar cgruber avatar chang-eric avatar chmuche avatar cpovirk avatar cushon avatar dependabot[bot] avatar dimo414 avatar eamonnmcmanus avatar fbiville avatar gk5885 avatar jakewharton avatar java-team-github-bot avatar jiangji avatar jlavallee avatar kluever avatar kush-c avatar lowasser avatar matvore avatar mbrukman avatar netdpb avatar ronshapiro avatar sameb avatar stefanhaustein avatar sullis avatar velo avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

compile-testing's Issues

NPE when generated source is package-info.java

My annotation processor generates package-info.java source files.
But when I call generatesSources() NPE is thrown?

java.lang.NullPointerException
    at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:213)
    at com.google.common.collect.FluentIterable.<init>(FluentIterable.java:82)
    at com.google.common.collect.FluentIterable$1.<init>(FluentIterable.java:91)
    at com.google.common.collect.FluentIterable.from(FluentIterable.java:90)
    at com.google.testing.compile.TypeEnumerator$TypeScanner.visitCompilationUnit(TypeEnumerator.java:103)
    at com.google.testing.compile.TypeEnumerator$TypeScanner.visitCompilationUnit(TypeEnumerator.java:55)
    at com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:550)
    at com.sun.source.util.TreeScanner.scan(TreeScanner.java:77)
    at com.google.testing.compile.TypeEnumerator$TypeScanner.scan(TypeEnumerator.java:59)
    at com.google.testing.compile.TypeEnumerator.getTopLevelTypes(TypeEnumerator.java:49)
    at com.google.testing.compile.JavaSourcesSubject$CompilationClause$1.apply(JavaSourcesSubject.java:178)
    at com.google.testing.compile.JavaSourcesSubject$CompilationClause$1.apply(JavaSourcesSubject.java:176)
    at com.google.common.collect.Maps.toMap(Maps.java:1119)
    at com.google.common.collect.Maps.toMap(Maps.java:1097)
    at com.google.testing.compile.JavaSourcesSubject$CompilationClause.parsesAs(JavaSourcesSubject.java:183)
    at com.google.testing.compile.JavaSourcesSubject.parsesAs(JavaSourcesSubject.java:93)
    at com.google.testing.compile.JavaSourcesSubject$SuccessfulCompilationBuilder.generatesSources(JavaSourcesSubject.java:482)
    at com.nemesis.platform.core.mixin.processor.MixInAnnotationProcessorTest.test(MixInAnnotationProcessorTest.java:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

assertAbout(javaSources())
                        .that(ImmutableList.of(JavaFileObjects.forResource(Resources.getResource("definition/package-info.java"))))
                        .processedWith(new MixInAnnotationProcessor())
                        .compilesWithoutError().and()
                        .generatesSources(JavaFileObjects.forResource(Resources.getResource("entity/package-info.java")));

Proposition for counts of warnings/errors

There are times you're testing an error, but a different error (or warning) accompanies it. It would be good to have predicates to assert hte number of errors/warnings so you know you're not testing for error contents, but letting unexpected errors through.

Compile generated code and execute it

Hi @cgruber ,

is it possible to compile generated code and execute it via compile-testing ?
I mean compile the code that an annotation processor created, and use the compiled classes ?

If not, how would you do ?

Unknown variable type java.util.Map<java.lang.String,java.lang.Integer> for declared

I don't know if I am doing something wrong but this seems odd to me.

To reproduce this:

@Test
public void testMap() {
    final JavaFileObject actualSource = JavaFileObjects.forSourceString("test/MapTest", Joiner.on('\n').join(
        "package test;",

        "import nsmodelextractor.Extract;",

        "import java.util.Map;",
        "import java.lang.String;",
        "import java.lang.Integer;",

        "public class MapTest {",
            "@Extract Map<String, Integer> map = null;",
        "}")
    );

    assertAbout(javaSource()).that(actualSource).compilesWithoutError();
}

The extract annotations looks like this

@Retention(CLASS)
@Target(FIELD)
public @interface Extract {
    String name() default "";
}

I also tried it without any imports. However I keep on getting

Unknown variable type java.util.Map<java.lang.String,java.lang.Integer> for declared

I'm using com.google.testing.compile:compile-testing:0.7

Guava mismatch between compile-testing and tools.jar causes runtmie issues.

When I use multiple annotation processors (via the .processedWith() API), I get this runtime exception:

java.lang.RuntimeException: java.lang.NoSuchMethodError: com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable;
    at com.sun.tools.javac.main.Main.compile(Main.java:553)
    at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
    at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
    at com.google.testing.compile.Compilation.compile(Compilation.java:76)
    at com.google.testing.compile.JavaSourcesSubject$CompilationClause.successfulCompilationResult(JavaSourcesSubject.java:298)
    at com.google.testing.compile.JavaSourcesSubject$CompilationClause.compilesWithoutError(JavaSourcesSubject.java:288)

I think the Java tools jar is also using Guava, but a very old version with different APIs.

Resource files not outputted

I have an annotation processor that produces both some java source files and an xml file.
When the compilation fails, though, only the contents of the generated java files is shown and the xml file seems to be ignored, even though it should effectively have been generated.

The xml file is outputted in the SOURCE_OUTPUT location and uses the standard Filer methods.

The generatesFileNamed() method to does report the file to be present.

Node erroneously marked as MEMBER_SELECT when actually IDENTIFIER

Expected code:

return new AutoValue_Foo(
    (CharSequence) in.readCharSequence()
);

Actual:

return new AutoValue_Foo(
    (java.lang.CharSequence) in.readCharSequence()
);

Diff failure:

> Difference in expected tree and actual tree.
  Expected node: Line 36 COMPILATION_UNIT->CLASS(AutoValue_Foo)->VARIABLE(CREATOR)->NEW_CLASS->CLASS()->METHOD(createFromParcel)->BLOCK(non-static)->RETURN->NEW_CLASS->TYPE_CAST->IDENTIFIER(CharSequence)->IDENTIFIER(CharSequence)
  Actual node: Line 36 COMPILATION_UNIT->CLASS(AutoValue_Foo)->VARIABLE(CREATOR)->NEW_CLASS->CLASS()->METHOD(createFromParcel)->BLOCK(non-static)->RETURN->NEW_CLASS->TYPE_CAST->MEMBER_SELECT(CharSequence)->MEMBER_SELECT(CharSequence)
  Expected node kind to be <IDENTIFIER> but was <MEMBER_SELECT>.

Access to Filer, assert about generated files

Access to the Filer is trivial to add to CompilationRule. What I can't figure out is how to propagate the generated content back to the test to assert on the generated sources. At the very least it would require a change to Compilation to inject the InMemoryJavaFileManager so it could also be made available to the test but that brings other dependencies with it. Perhaps Compilation should be more stateful than just static helpers?

I'm not doing any actual compilation. I want to only test interactions with a Filer and assert on its outputs.

Happy to implement, just want guidance/approval on the approach.

Pretty diffs

Long shot, and no urgent need, but diff-ish comparisons in a few areas would be nice - In the case of partial matches in withErrorContaining() the partial match could be expressed, with the delta being called out. similarly in the case of properly named, but content-differing generated sources. Some sort of diff of the sort similar to what Assert.assertEquals(String,String) does would be the idea, from a UI perspective.

compilesWithoutError failure is hard to understand without the generated sources.

If I have a generated source with a compile error, it is difficult to understand what the error is from the error message alone since there is no easy way to compare to the actual source.

It would be nice if the error message dumped a copy of the source file annotated with the compile errors. In general having easier access to the generated sources would make iterative test development easier.

Need a .generatedNoFiles() proposition.

This is important both in terms of asserting that a compiltion run doesn't produce files when it isn't supposed to, but could also in the error list all generated files in that compile job, and be useful to debug the processor, since that list is hard to know/discover without going to the filesystem and digging.

Add unit test for the 3rd package-info.java example.

Currently there is not a unit test that matches the 3rd example in the package-info.java file:

 assert_().about(javaSource())
     .that(JavaFileObjects.forResource("HelloWorld.java"))
     .processedWith(new MyAnnotationProcessor())
        .compilesWithoutError()
        .and().generatesSources(JavaFileObjects.forResource("GeneratedHelloWorld.java"));

As I (and others) have had difficulty getting this to work a unit test for this example would be helpful.

JavaFileObjects violates StandardJavaFileManager contract wrt toUri

JavaFileObjects violates StandardJavaFileManager contract wrt toUri:

The URI returned from FileObject.toUri()

  • must be absolute (have a schema), and
  • must have a normalized path component which can be resolved without any process-specific context such as the current directory (file names must be absolute).

According to these rules, the following URIs, for example, are allowed:

  • file:///C:/Documents%20and%20Settings/UncleBob/BobsApp/Test.java
  • jar:///C:/Documents%20and%20Settings/UncleBob/lib/vendorA.jar!com/vendora/LibraryClass.class

Whereas these are not (reason in parentheses):

  • file:BobsApp/Test.java (the file name is relative and depend on the current directory)
  • jar:lib/vendorA.jar!com/vendora/LibraryClass.class (the first half of the path depends on the current directory, whereas the component after ! is legal)
  • Test.java (this URI depends on the current directory and does not have a schema)
  • jar:///C:/Documents%20and%20Settings/UncleBob/BobsApp/../lib/vendorA.jar!com/vendora/LibraryClass.class (the path is not normalized)

— Source: http://docs.oracle.com/javase/7/docs/api/javax/tools/StandardJavaFileManager.html

The javadoc for JavaCompiler gives an example of implementation for a string-based JavaFileObject:

For example, here is how to define a file object which represent source code stored in a string:

      /**
       * A file object used to represent source coming from a string.
       */
      public class JavaSourceFromString extends SimpleJavaFileObject {
          /**
           * The source code of this "file".
           */
          final String code;

          /**
           * Constructs a new JavaSourceFromString.
           * @param name the name of the compilation unit represented by this file object
           * @param code the source code for the compilation unit represented by this file object
           */
          JavaSourceFromString(String name, String code) {
              super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),
                    Kind.SOURCE);
              this.code = code;
          }

          @Override
          public CharSequence getCharContent(boolean ignoreEncodingErrors) {
              return code;
          }
      }

Note how they prefix the URI with "string:///" (it's otherwise equivalent to what JavaFileObjects.forSourceString does).

AFAICT, this is an issue only for forSourceString (and forSourceLines, which ultimately defer to forSourceString), and forResource when the resource is in a JAR (e.g. not if it's a file).

in() should be optional for single-source subject assertion chains

Admittedly I'm pretty new to compile-testing, but I have found in my short time that the bulk of my tests consist of single source files that are designed either to exercise particular error conditions in my annotation processor. Of course given that only one file is being compiled the error will always be in that file. Currently, however, in the javaSource() subject, you still have to specify in() when checking the errors. Instead of:

ASSERT.about(javaSource())
    .that(file)
    .failsToCompile()
    .withErrorContaining("error msg")
    .in(file).onLine(1).atColumn(6);

...I'd like to be able to omit in():

ASSERT.about(javaSource())
    .that(file)
    .failsToCompile()
    .withErrorContaining("error msg")
    .onLine(1).atColumn(6);

I think it would be good to still have in() as an option (because the error might conceivably happen in another file other than your single source - eg, a generated file). However, I have already come across this pattern so many times that I think it would be a useful enhancement.

0.10's CompilationSubject is missing an equivalent of GeneratedPredicateClause.generatesSources

To assert the source generation with 0.9, I did

            assert_().about(javaSource()).that(inputJFO)
                .processedWith(new MyProcessor())
                .compilesWithoutError()
                .and().generatesSources(expectedJFO);

where input and expected are JavaFileObjects.

With 0.10

        Compilation compilation = Compiler.javac().withProcessors(new MyProcessor()).compile(inputJFO);
        CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
        CompilationSubject.assertThat(compilation).generatedSourceFile(…);

I hope it's just there and I might have overlooked it.

Fails in Java6 projects when using deployed artifact.

Due to subtle issues iwth java6/java7 and the com.sun.tools.javac.api crap, NoSuchMethodErrors are being thrown when deployed artifact is being used with any Java6 API.

java.lang.NoSuchMethodError: com.sun.tools.javac.api.JavacTool.getStandardFileManager(Ljavax/tools/DiagnosticListener;Ljava/util/Locale;Ljava/nio/charset/Charset;)Lcom/sun/tools/javac/file/JavacFileManager;
    at com.google.testing.compile.Compilation.compile(Compilation.java:60)
    at com.google.testing.compile.JavaSourcesSubject$CompilationClause.compilesWithoutError(JavaSourcesSubject.java:89)
    at my.tests..MyTest.testFoo(MyTest.java:75)
        ...

Not sure why - the API doesn't SEEM to have changed between versions, though I might have missed it. The call in question might need to be made reflectively in order to try one, then the other. But we should build it in 6 so it can be used in 6, and deploy from that build, OR we should decide that Java6 is not supported and document it.

Implement Subject for multiple sources

My usecase would be to process two classes at once, with the fictional API:

import static com.google.testing.compile.JavaFileObjects.forResource;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
import static org.truth0.Truth.ASSERT;
// [...]

ASSERT.about(javaSource())
            .that(forResource("MyFirstClass.java", "MySecondClass.java")) // fictional: only 1 JFO in current API
            .processedWith(new MyProcessor())
// [...]

It seems JavaSourcesSubject is already designed for multiple source support. However, the only exposed class is JavaSourceSubjectFactory which in turn relies on SubjectFactory<SingleSourceAdapter, JavaFileObject>.

generatesSources() fails, but doesn't attempt to compare like to like

generatesSources() scans all sources for all expected sources, but in the case of a failure, only reports boolean failure. In the case where code is improperly generated, but some code is generated purportedly against a given type/filename, there is no display of "expected" vs. "actual" for comparison, and the user is left to guess at the result.

I wonder if the scanning could be done at the level of filename first, seeing if a file was generated as expected at all - since JavaSourceFile does already contain a notion of filename. THEN the equality scanner could be used against the result, and if there is failure, show "expected this, but got that". The current model is better than string comparison, but still too brittle to be truly useful.

Ability to list output files of a compilation

If someone wants to create tests for existing annotation processor which generates files (xml description for example) from java files, then it is hard to figure out after a compilation what kind of files with what content were generated. I can check the content of some files ONLY if I know that they were generated. Today the list of generated files is encapsulated into InMemoryJavaFileManager.

It would be really good to have some alternative to that. I have thought about something like that:

assert_().
  about(javaSource()).
  that(JavaFileObjects.forResource( "Some.java") ).
  processedWith( new MyAnnotationProcessor() ).
  compilesWithoutError(an_instance_of_org_junit_rules_TemporaryFolder.getRoot());

The JavaFileManager could save the output files into the temp folder as well. Then the test case could easily check and see the list and contents of generated files.

I am surely not aware of the whole concept, so correct me please if my idea is somehow not realistic.

Unable to create resource content in code.

StringSourceJavaFileObject (via forSourceString) assumes I'm creating a SOURCE object when I want to create an OTHER (resource file).

In @AutoService you use actual resources as the expected generated content. I prefer to keep both the originating source and generated sources in the actual test so everything is in one place.

String source = ""
    + "package com.example;\n"
    + "\n"
    + "import com.example.auto.resource.thingy.AutoResourceThingy;\n"
    + "\n"
    + "@AutoResourceThingy\n"
    + "public class Example {}";
JavaFileObject sourceFile = JavaFileObjects.forSourceString("com.example.Example", source);

JavaFileObject expectedSource =
    JavaFileObjects.forSourceString("META-INF/thingy/com.example.Example",
        "THINGY!");

ASSERT.about(javaSource()).that(sourceFile)
    .processedWith(autoResourceThingy())
    .compilesWithoutError()
    .and()
    .generatesFiles(expectedSource);

Java 8 missing a method

$ java -version
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b111)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b53, mixed mode)
java.lang.NoSuchMethodError: com.sun.source.tree.NewArrayTree.getDimensions()Ljava/util/List;
    at com.google.testing.compile.EqualityScanner.visitNewArray(EqualityScanner.java:338)
    at com.google.testing.compile.EqualityScanner.visitNewArray(EqualityScanner.java:87)
    at com.sun.tools.javac.tree.JCTree$JCNewArray.accept(JCTree.java:1568)
    at com.google.testing.compile.EqualityScanner.scan(EqualityScanner.java:102)
    at com.google.testing.compile.EqualityScanner.visitVariable(EqualityScanner.java:482)
    at com.google.testing.compile.EqualityScanner.visitVariable(EqualityScanner.java:87)
    at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:858)
    at com.google.testing.compile.EqualityScanner.parallelScan(EqualityScanner.java:110)
    at com.google.testing.compile.EqualityScanner.visitClass(EqualityScanner.java:199)
    at com.google.testing.compile.EqualityScanner.visitClass(EqualityScanner.java:87)
    at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:714)
    at com.google.testing.compile.EqualityScanner.parallelScan(EqualityScanner.java:110)
    at com.google.testing.compile.EqualityScanner.visitCompilationUnit(EqualityScanner.java:408)
    at com.google.testing.compile.JavaSourcesSubject$SuccessfulCompilationBuilder$1.apply(JavaSourcesSubject.java:263)
    at com.google.testing.compile.JavaSourcesSubject$SuccessfulCompilationBuilder$1.apply(JavaSourcesSubject.java:260)
    at com.google.common.collect.Iterators$7.computeNext(Iterators.java:647)
    at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
    at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
    at com.google.common.collect.Iterators.tryFind(Iterators.java:747)
    at com.google.common.collect.Iterables.tryFind(Iterables.java:672)
    at com.google.testing.compile.JavaSourcesSubject$SuccessfulCompilationBuilder.generatesSources(JavaSourcesSubject.java:259)
    at dagger.tests.integration.codegen.InjectAdapterGenerationTest.providerForCtorInjection(InjectAdapterGenerationTest.java:170)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

generateSources cannot find JavacTool

When I have ....generateSources(JavaFileObjects.forSourceString("HelloWorld", "public class HelloWorld { }\n")); I get an error (see below), this is true even if I use forResource(String) for a file I used in the source list to ASSERT.about(javaSources()).that(...). Everything else works, it seems to be some sort of configuration issue.

ERROR!
java.lang.NoClassDefFoundError: com/sun/tools/javac/api/JavacTool
    at com.google.testing.compile.Compilation.parse(Compilation.java:86)
    at com.google.testing.compile.JavaSourcesSubject$SuccessfulCompilationBuilder.generatesSources(JavaSourcesSubject.java:255)
    at com.imminentmeals.prestige.codegen.TestController.testControllerForPresentationWithProtocol(TestController.java:167)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103)
    at $Proxy0.invoke(Unknown Source)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69)
Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.api.JavacTool
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 32 more

EqualityScanner#visitLiteral does not handle null

For the code:

if (foo == null) {
 // Do stuff
}

Produces a NullPointerException when trying to call .equals on null.

    return other.isPresent()
        && reference.getValue().equals(other.get().getValue());

Add "generatesSourcesExactly" method?

Currently if you call GeneratedPredicateClause.generatesSources(foo) but the code generates two files instead of just foo, this test will pass. If I were to add a generateSourcesExactly that requires all generated files be specified, would that be accepted?

generatesSources() exhibits confusing behavior for inexact path matches

Assume that a generatesSources() clause is evaluated under the following conditions:

  • All the generated sources are parseable
  • All of the expected sources are parseable
  • There is at least one mismatch between the URI of the expected source list and the compiled source list

If each one of the generated sources can be paired with an expected source having an equal compilation tree, then the clause succeeds

However, if at least one generated source cannot be paired with a syntactically equal expected source, then the clause will fail with the message "Did not find a source file named ..."

The error indicates that the failure was due to a mismatched path, when in fact the clause will succeed without changing any path at all.

Plain JUnit support/example needed (without org.truth0.Truth stuff)

Compile-testing is cool but even nicer if it can be used with plain JUnit tests also as I would like to limit dependencies and not using different test frameworks for different libraries. Especially since Truth is very alpha, and subject to change according to the docs.

Use compile-testing & Truth plus runtime testing

I want to test my processor and test the classes autogenerated by it. I am getting a class not found error when i do my testing code like:

@Before public void setup() {
    JavaFileObject source = JavaFileObjects.forSourceString("com.github.jorgecastilloprz.corleone.Test", Joiner.on('\n')
        .join("package com.github.jorgecastilloprz.corleone;",
            "public class Test {",
           "...stuff..."
            "}"));

    //Truth assertion
    Truth.ASSERT.about(javaSource())
        .that(source)
        .processedWith(myProcessor())
        .compilesWithoutError();
  }

  @Test public void jobDispatchTest() {
    JobDispatcher.getInstance().dispatchJobsWithContext("ObtainGames");
  } 

The dispatchJobsWithContext does a Class.forName() call inside it. I suppose the problem is that compile testing is prepared to test @ compile time, and that is the scope i am testing in. How can i reach the runtime to test autogenerated classes then?

Thanks in advance.

InMemoryJavaFileManager has different behavior than standard java file manager.

The InMemoryJavaFileManager allows locations other than those specified in StandardLocation, whereas the standard manager will throw a null pointer exception if a non standard location is used.
Please look at a simple unit test i made which illustrates this

While it now seems kind of obvious to me that the "standard" manager would only support "standard" locations, it would be nice if compile-testing checked that it's backing file manager was actually able to create a FileObject for the specified location.

Support ecj

The eclipse compiler has a lot of quirks that make it incompatible with the current code. E.g.: different treatment of the classNames param and requiring all JavaFileObjects be Files

Alternate propositions for generated source

I'm thinking of something on the order of

ASSERT.about(javaSources()).that(source)
    .compileswithoutError().and()
    .generatesSourceAtPath("path").containingSnippets("some valid snippet").and()
    .generatesSourceAtPath("path").containingMethods(
        "method signature1", 
        "method signature2").and()
    .generatesSourceAtPath("path").containingFields(
        "String foo", 
        "private Blah blah").and()
     ...

Doesn't have to be exactly like this, and the snippets version could stand in for all the rest. But it would be nice to ask things about the generated output while testing.

Add support for compiler options

The API does not allow to pass options to javac, which is useful for turning on verbose mode or passing options to annotation processors.

Constructor names are not compared

Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
                .that(givenJavaFile)
                .processedWith(someProcessor)
                .compilesWithoutError()
                .and()
                .generatesSources(expectedJavaFile);

Expected and generated constructor names are not compared.
Obviously it will fail later at generated source compilation if name is wrong, but it would be nice to detect it in generated sources comparison to make tests fail if such error occurs.

Generated:

public class Generated {
  public Generated() {
  }
}

Expected:

public class Generated {
  public GeneratedWithBadName() {
  }
}

With the previous examples, comparison does not fail.

Ability to compile JavaFileObjects and access Elements/Types

I have a need to access the mirror-based instances of elements and types in order to unit test code which deals with them after compiling supplied JavaFileObject instances.

Currently this library only assumes I either want "empty" Elements or Types instance from the rule or that I want to assert about the compilation of JavaFileObjects (optionally processed through some processor). This would be an API that sat between the two allowing for the same compilation of JavaFileObjects but then providing me access to the Elements and Types instances from that compilation.

For this I was thinking of a Compilation class which facilitated building what was to be compiled and any annotation processors to run. Calling .compile produced a Compilation.Result containing methods for access to the exit code, Elements, Types, and generated files (this would solve #58).

Additionally, another subject factory would be added for asserting about a Compilation.Result. Ideally supporting this use-case would simply mean putting a cleaner API around what's already happening internally and then refactoring the current assertion-based usage to use this new API directly.

A contrived example:

String input = ""
    + "package example;\n"
    + "public final class Example {}";
String inputFile = JavaFileObjects.forSourceString("example.Example", input);

Compilation.Result result = Compilation.builder()
    .addFileObject(inputFile)
    //.addProcessor(..)
    .compile();

Elements elements = result.elements();
TypeElement example = elements.getTypeElement("example.Example");
assertThat(SomeUtility.validateSomething(example)).isTrue();

hasError(message) fails on MacOS Runtime for Java

Diagnostic internals on MacOS RUntime for Java seem to prepend the canonical file and line number to the message in a way that OpenJDK doesn't, where hasError() is matching on message. So "not a statement" becomes "/some/path/to/project/src/main/resources/HelloWorld-broken.java:23: not a statement", thus causing the hasError() to fail inappropriately.

Solution seems to test for a mac JVM and apply an alternate matcher (or try one, then the Mac one as a fallback)

A good example is missing

I had to run through a bunch of classes to find out where the assert_() call was coming from in the doc.
The doc could be better for this and a nice little sample would be valuable.

assertion result method .onLine(X) does not report the lines on which errors were found.

Repro steps.

  @Test public void testFoo() {
    JavaFileObject sourceFile = JavaFileObjects.forSourceString("Foo", ""
        + "class Foo extends Bar {\n"
        + "}");

    ASSERT.about(javaSource())
        .that(sourceFile)
        .hasErrorContaining("cannot find symbol").in(sourceFile).onLine(2);
  }

The following is seen instead of providing the lines on which errors are found.

java.lang.AssertionError: Expected an error on line 2, but only found errors on line(s) []
    at org.truth0.Truth$1.fail(Truth.java:57)
    at com.google.testing.compile.JavaSourcesSubject$UnsuccessfulCompilationBuilder$3$3.onLine(JavaSourcesSubject.java:201)
    at ...

Assert non-existence of a particular error

In the annotation processor that I am working on, I have run across a case where it is meaningless to report error2 if error1 is detected. Thus as a feature I would like my processor to not output error2 if it has output error1, and I would like to test that my processor is doing the right thing.

Unfortunately the current API doesn't provide for this case easily, as it only allows you to assert the existence of a particular error, or the non-existence of all errors.

In my tests I got around this problem by testing for the existence of error2 using withErrorContaining(), wrapping it in a try/catch, and silently continuing if no AssertionError is caught or else throwing my own AssertionError if it wasn't. However, this is a little ugly and the diagnostics are not as informative as they might be with a "native" implementation in the compile-testing API itself.

I would like to be able to do something like:

failsToCompile().withErrorContaining(error1).in(file).onLine(line1).and()
                     .withNoErrorContaining(error2).in(file).onLine(line2);

generatesSources() requires that expected paths be exact suffixes of generated paths

The way the generatesSources() clause is implemented seems to indicate that it wants to enforce that the paths to expected sources be exact suffixes of the paths in all generated sources. This imposes an inconvenient structure on testing directories.

ResourceSourceJavaFileObjects are assigned a URI upon creation that is equal to the resource path. generatesSources() has a failure mode which is triggered when !generatedResourceURI.getPath().endsWith(expectedResourceURI.getPath()).

This forces users to put the resources that contain expected sources in the target directory for their corresponding generated sources.

Generating other than .java files testing

I am trying to generate an HTML out fro annotated classes and i need to write unit testing for the generated .html files:

when i am generating .java files i testing them like this:

Truth.assert_().about(javaSource()).that(JavaFileObjects.forResource("source class .java goes here"))
                .processedWith(new UiFormProcessor()).compilesWithoutError()
                .and()
                .generatesSources(JavaFileObjects.forSourceString("","expected generated class content goes here"));

and that works for me very well.

but when i am trying to generate an .html file and use the same code above, it result in an error like this
java.lang.AssertionError: Did not find a generated file corresponding to .java

its seems that the generated files are expected to be java files all the time, i have been trying to figure out if i am calling the wrong methods or passing wrong arguments, but i could'nt make it work.

is there anyway to test none java generated sources like hml with this tool?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.