Why Would Doppl Fail To Find a Unit Test Class? - doppl

When trying to run JUnit tests for a Doppl-converted project, I am crashing with:
Terminating app due to uncaught exception 'JavaLangRuntimeException', reason: 'java.lang.RuntimeException: java.lang.ClassNotFoundException: co.doppl.so.RepositoryTest'
So, the JUnit code is failing to find my test class (co.doppl.so.RepositoryTest).
The class is included in my dopplConfig:
dopplConfig {
translatePattern {
include 'co/doppl/so/api/**'
include 'co/doppl/so/arch/**'
include 'co/doppl/so/RepositoryTest.java'
}
translatedPathPrefix 'co.doppl.so', 'SO'
translatedPathPrefix 'co.doppl.so.api', 'SOAPI'
translatedPathPrefix 'co.doppl.so.arch', 'SOA'
testIdentifier {
include 'co/doppl/so/RepositoryTest.java'
}
}
I see SORepositoryTest.h and SORepositoryTest.m in app/build/j2objcSrcGenTest/. The prefixes.properties file seems correct:
#Sat Oct 28 14:44:00 EDT 2017
co.doppl.so=SO
co.doppl.so.arch=SOA
co.doppl.so.api=SOAPI
The dopplTests.txt lists the class that cannot be found:
co.doppl.so.RepositoryTest
My ViewController.swift file is pulling in that dopplTests.txt file:
import UIKit
import testdoppllib
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
CoTouchlabDopplTestingDopplJunitTestHelper.runResource(with: "dopplTests.txt")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Why would Doppl's JUnit stuff fail to find this class?

This seems to be a bug/limitation/something with the current Doppl, where tests cannot be renamed using translatePathPrefix.

Related

How to use Dagger for Groovy?

How to configure dagger to inject groovy classes, and to inject into groovy classes?
I was initially trying to get dagger to inject a groovy class into my java app, and I found dagger was complaining the groovy class is not found. Looking at the log, it seems that compileGroovy happens after compileJava. And the annotation processing of dagger compiler seems to be in compileJava. I guessed that might be the problem -- no groovy classes are available at this time. But I've yet figured out a way to coerce either of dagger or groovy to work with the other.
It seems I could not upload a .tar.gz. But if anyone needs a minimal demo code for what I meant to achieve, these might help (with gradle 7):
build.gradle:
plugins {
id 'groovy'
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
annotationProcessor 'com.google.dagger:dagger-compiler:2.+'
implementation 'com.google.dagger:dagger:2.+'
implementation 'org.codehaus.groovy:groovy-all:3.+'
}
settings.gradle:
rootProject.name = 'groovy-dagger1'
src/main/groovy/org/example/dagger/MainComponent.groovy:
package org.example.dagger
import dagger.Component
#Component(modules = [
MainModule,
])
interface MainComponent {
String message();
}
src/main/groovy/org/example/dagger/MainModule.groovy:
package org.example.dagger
import dagger.Module
import dagger.Provides
#Module
final class MainModule {
#Provides
static String message() {
return 'Hello Groovy Dagger!'
}
}
src/main/groovy/org/example/main/Main.groovy:
package org.example.main;
class Main {
static void main(String[] args) {
// Dagger component does not exist :/
// println DaggerMainComponent.create().message()
}
}
By default, the groovy compiler will not run the java annotation processors...
You can add this to your build.gradle:
compileGroovy {
groovyOptions.javaAnnotationProcessing = true
}
You will of course need to add an import
import org.example.dagger.DaggerMainComponent
To Main.groovy

Running Groovy test cases with JUnit 5

Maybe this is very simple, but I couldn't find any examples on the web:
I'd like to use JUnit 5 to run a unit test implemented as a Groovy class. My current setup seems to launch JUnit 5, but fail to detect the test case. IntelliJ recognizes the test, but fails to run it. If I add a Java unit test, it is launched correctly.
Here's what I have now:
Project structure
src
main
groovy
# production code
test
groovy
UnitTest.groovy
build.gradle
...
build.gradle
plugins {
id 'groovy'
}
dependencies {
compile localGroovy()
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.1'
}
test {
useJUnitPlatform()
}
UnitTest.groovy
import org.junit.jupiter.api.Test
class UnitTest {
#Test
def shouldDoStuff() {
throw new RuntimeException()
}
}
I'm using Gradle 4.10.
Any ideas?
JUnit requires all testing method to use return type void. Groovy's def keyword is compiled to an Object type, so your method compiles to something like this in Java:
import org.junit.jupiter.api.Test
public class UnitTest {
#Test
Object shouldDoStuff() {
throw new RuntimeException();
}
}
If you try this out as a Java test, it won't find the test case neither. The solution is very simple - replace def with void and your Groovy
test case will be executed correctly.
src/test/groovy/UnitTest.groovy
import org.junit.jupiter.api.Test
class UnitTest {
#Test
void shouldDoStuff() {
throw new RuntimeException()
}
}
Demo:

Core Data Framework With Multiple Targets

I am currently making a project in swift 4 which uses a few targets. Since all the targets need to access the same core data, I have decided to make my own framework target which stores the data model for it as well as the access information for it.
The problem I am having is in my application target (CoreDataTest), when I run the application, I get the following error:
2017-09-17 12:02:20.787132+0100 CoreDataTest[22070:3218298] [error] error: Failed to load model named TestData
CoreData: error: Failed to load model named TestData
2017-09-17 12:02:20.787594+0100 CoreDataTest[22070:3218298] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An NSManagedObject of class 'Message' must have a valid NSEntityDescription.'
*** First throw call stack:
(0x182097d38 0x1815ac528 0x18481a73c 0x1026c6678 0x1026c6708 0x1848bac5c 0x10261d480 0x10261ce94 0x10261cd48 0x10261cecc 0x18b42b96c 0x18b42b544 0x18b43210c 0x18b42f378 0x18b49edb4 0x18b68e570 0x18b693300 0x18b9129b4 0x18bbd90d0 0x18b912618 0x18b912e88 0x18c05daf4 0x18c05d998 0x18bde7ab4 0x18bf77c94 0x18bde7964 0x18bbd8730 0x18b691a44 0x18ba80144 0x18472d968 0x184736270 0x10344145c 0x10344db74 0x184761b04 0x1847617a8 0x184761d44 0x182040358 0x1820402d8 0x18203fb60 0x18203d738 0x181f5e2d8 0x183de3f84 0x18b48f5e0 0x10261deec 0x181a8256c)
libc++abi.dylib: terminating with uncaught exception of type NSException
I added an exception break point and it crashes in ViewController.swift at PersistenceStorage.saveContext().
How would I create a framework to create a shared Core Data database throughout my multiple targets in a single project?
Here is my project setup. Please note that each group is its own target.
Target: CoreDataKit (Framework)
CoreData.swift
import CoreData
public class PersistenceStorage {
private init() {}
public static var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
public static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "TestData")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
public static func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Message+CoreDataClass.swift
import Foundation
import CoreData
#objc(Message)
public class Message: NSManagedObject {
}
Message+CoreDataProperties.swift
import Foundation
import CoreData
extension Message {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Message> {
return NSFetchRequest<Message>(entityName: "Message")
}
#NSManaged public var text: String?
}
Target: CoreDataTest (Main Application)
ViewController.swift
import UIKit
import CoreDataKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let message = Message(context: PersistenceStorage.context)
message.text = "test"
PersistenceStorage.saveContext()
}
}
AppDelegate.swift
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
}
After a lot of research and trial and error, I found that I need to set the target members on the xcdatamodel file to the other targets that I wanted it to be shared with.
Just bumped into this myself so thought I'd post a couple other options.
Since you aren't subclassing NSPersistentContainer then it doesn't know where to look for bundles so has no option but to look in the main bundle.
If you want to only have your model in your framework then you could subclass NSPersistentContainer, or you can load the model first and pass that to the initialization of the persistent container. If you have only a single model then doing something like mergedModelFromBundles is pretty simple to do and then pass that model to the persistent container initializer.

How to use multiple classes in multiple files in scripts?

I need to make a standalone Groovy script that does not require compilation and runs without Groovy installed. It works well, but it fails to recognize any other script than the main script.
My folder structure is the following:
libs\
groovy-all-2.4.3.jar
ivy-2.4.0.jar
src\
makeRelease.groovy
ReleaseHelper.groovy
I am launching the script this way from the src folder:
java -cp "../libs/*" makeRelease.groovy
makeRelease looks like this:
public class makeRelease {
public static void main(String... args) {
new ReleaseHelper()
...
}
}
When run this is the output:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
src\makeRelease.groovy: 5: unable to resolve class ReleaseHelper
How can I include other classes (that reside in separate files) in such portable scripts?
I think that it is easier than you think:
libs\
groovy-all-2.4.3.jar
src\
main.groovy
Greeter.groovy
Where main.groovy
public class Main {
public static void main(args) {
println 'Main script starting...'
def greeter = new Greeter()
greeter.sayHello()
}
}
and Greeter.groovy
class Greeter {
def sayHello() {
println 'Hello!'
}
}
Simply add to the classpath the folders where you have the classes in separate files:
java -cp .;..\libs\groovy-all-2.4.3.jar groovy.ui.GroovyMain main.groovy
The above yields:
Main script starting...
Hello!

How to use import inside a dynamically loaded groovy file

I am trying to come up with a way for my users to supply plugins into the main groovy application by dynamically loading their source file. But their groovy file contains import statements and I don't know how to make them work even with an apparently good classpath.
The main application is a shell script, bin/top.sh:
#!/bin/bash
groovy-2.4.1/bin/groovy -cp lib lib/Top.groovy
The lib/Top.groovy class:
public class Top {
public static void main(String[] args) {
ClassLoader parent = getClass().getClassLoader()
GroovyClassLoader loader = new GroovyClassLoader(parent)
Class groovyClass = loader.parseClass(new File("UserPlugin.groovy"))
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance()
groovyObject.invokeMethod("run",args)
}
}
The user class UserPlugin.groovy:
// The following import can be found in the classpath
// passed by the shell script (under lib/, next to Top.groovy)
import Lib
class UserPlugin {
def UserPlugin() {
Lib lib = new Lib()
}
def run(String [] args) {
println("Running with: "+args)
}
}
And the lib/Lib.groovy:
class Lib {
def Lib() {
println("Lib")
}
}
When I run with bin/top.sh, I get: UserPlugin.groovy: 3: unable to resolve class Lib
When I add lib to the class loader like so loader.addClasspath('lib'), it's rather catastrophic:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during class generation: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
java.lang.RuntimeException: java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
at org.codehaus.groovy.control.CompilationUnit.convertUncaughtExceptionToCompilationError(CompilationUnit.java:1088)
How can this work while keeping it all scripted and not compiled? Is this even possible?
Sorry I don't have time to find the bug but I think the problem is with the setting of the context classloader. GroovyShell.run takes care of that for you which I recommend over replicating that code.
Top.groovy
public class Top {
public static void main(String[] args) {
new GroovyShell().run(new File("UserPlugin.groovy"), args)
}
}
If you're willing to make Top.groovy a script rather than class then you can do this:
Top.groovy
run(new File("UserPlugin.groovy"), args)
The UserPlugin.groovy then needs to be either a class (with a main method) or a script to use the standard Groovy calling logic.

Resources