diff --git a/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegate.groovy b/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegate.groovy index 636e974..6bcdfda 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegate.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegate.groovy @@ -22,7 +22,8 @@ abstract class AbstractBuildDelegate { this.siteSpecClosures.inject(SiteSpec.getBlank()) { acc, closure -> def d = new SiteSpecDelegate() closure.delegate = d - closure.resolveStrategy = DELEGATE_FIRST + //noinspection UnnecessaryQualifiedReference + closure.resolveStrategy = Closure.DELEGATE_FIRST closure() acc + d.getResult() } @@ -32,7 +33,8 @@ abstract class AbstractBuildDelegate { this.globalsClosures.inject([:] as Map) { acc, closure -> def d = new GlobalsDelegate() closure.delegate = d - closure.resolveStrategy = DELEGATE_FIRST + //noinspection UnnecessaryQualifiedReference + closure.resolveStrategy = Closure.DELEGATE_FIRST closure() acc + d.getResult() } @@ -42,7 +44,8 @@ abstract class AbstractBuildDelegate { this.typesClosures.inject(TypesContainer.getEmpty()) { acc, closure -> def d = new TypesDelegate() closure.delegate = d - closure.resolveStrategy = DELEGATE_FIRST + //noinspection UnnecessaryQualifiedReference + closure.resolveStrategy = Closure.DELEGATE_FIRST closure() acc + d.getResult() } @@ -52,7 +55,8 @@ abstract class AbstractBuildDelegate { this.sourcesClosures.inject(SourceProviders.getEmpty()) { acc, closure -> def d = new SourceProvidersDelegate() closure.delegate = d - closure.resolveStrategy = DELEGATE_FIRST + //noinspection UnnecessaryQualifiedReference + closure.resolveStrategy = Closure.DELEGATE_FIRST closure(typesContainer) acc + d.getResult() } @@ -62,7 +66,8 @@ abstract class AbstractBuildDelegate { this.taskFactoriesClosures.inject([:] as Map) { acc, closure -> def d = new TaskFactoriesDelegate() closure.delegate = d - closure.resolveStrategy = DELEGATE_FIRST + //noinspection UnnecessaryQualifiedReference + closure.resolveStrategy = Closure.DELEGATE_FIRST closure(sourceProviders) def specs = d.getResult() specs.forEach { name, spec -> diff --git a/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegate.groovy b/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegate.groovy index 3c82fcc..41e25f7 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegate.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegate.groovy @@ -30,7 +30,11 @@ final class TaskFactoriesDelegate { this.specs[name] = new TaskFactorySpec<>(factorySupplier, [factoryConfigurator]) } - def void configure(String name, Class factoryClass, Consumer factoryConfigureClosure) { + def void configure( + String name, + Class factoryClass, // Dummy so we get better auto-complete + Consumer factoryConfigureClosure + ) { if (!this.specs.containsKey(name)) { throw new IllegalArgumentException("there is no TaskFactory registered by name ${ name }") } diff --git a/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractCollectionProvider.groovy b/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractCollectionProvider.groovy index 215e08e..d08d5ca 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractCollectionProvider.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractCollectionProvider.groovy @@ -1,19 +1,48 @@ package com.jessebrault.ssg.provider +import groovy.transform.EqualsAndHashCode +import groovy.transform.NullCheck +import groovy.transform.TupleConstructor + +@TupleConstructor(defaults = false, includeFields = true) +@NullCheck(includeGenerated = true) +@EqualsAndHashCode(includeFields = true) abstract class AbstractCollectionProvider implements CollectionProvider { + static CollectionProvider concat( + CollectionProvider cp, + Provider p + ) { + new SupplierBasedCollectionProvider<>([cp], [p], { + [*cp.provide(), p.provide()] + }) + } + static CollectionProvider concat( CollectionProvider cp0, CollectionProvider cp1 ) { - SupplierBasedCollectionProvider.get { + new SupplierBasedCollectionProvider<>([cp0, cp1], [], { cp0.provide() + cp1.provide() - } + }) + } + + private final Collection> collectionProviderChildren + private final Collection> providerChildren + + @Override + boolean contains(Provider provider) { + provider in this + } + + @Override + boolean contains(CollectionProvider collectionProvider) { + collectionProvider in this } @Override CollectionProvider plus(Provider other) { - concat(this, other as CollectionProvider) + concat(this, other) } @Override @@ -21,4 +50,23 @@ abstract class AbstractCollectionProvider implements CollectionProvider { concat(this, other) } + @Override + boolean isCase(Provider provider) { + provider in this.providerChildren || this.providerChildren.inject(false) { acc, childProvider -> + acc || provider in childProvider + } + } + + @Override + boolean isCase(CollectionProvider collectionProvider) { + collectionProvider == this + || collectionProvider in this.collectionProviderChildren + || this.collectionProviderChildren.inject( + false, + { acc, childCollectionProvider -> + acc || collectionProvider in childCollectionProvider + } + ) + } + } diff --git a/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractProvider.groovy b/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractProvider.groovy index 2cf51e1..9d3272a 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractProvider.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/provider/AbstractProvider.groovy @@ -6,9 +6,9 @@ abstract class AbstractProvider implements Provider { Provider p0, Provider p1 ) { - SupplierBasedCollectionProvider.get { + new SupplierBasedCollectionProvider<>({ [p0.provide(), p1.provide()] - } + }) } @Override @@ -18,9 +18,9 @@ abstract class AbstractProvider implements Provider { @Override CollectionProvider asType(Class collectionProviderClass) { - SupplierBasedCollectionProvider.get { + new SupplierBasedCollectionProvider<>({ [this.provide() as T] - } + }) } } diff --git a/api/src/main/groovy/com/jessebrault/ssg/provider/CollectionProvider.groovy b/api/src/main/groovy/com/jessebrault/ssg/provider/CollectionProvider.groovy index a338817..03a6aa9 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/provider/CollectionProvider.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/provider/CollectionProvider.groovy @@ -2,6 +2,13 @@ package com.jessebrault.ssg.provider interface CollectionProvider { Collection provide() + + boolean contains(Provider provider) + boolean contains(CollectionProvider collectionProvider) + CollectionProvider plus(Provider other) CollectionProvider plus(CollectionProvider other) + + boolean isCase(Provider provider) + boolean isCase(CollectionProvider collectionProvider) } \ No newline at end of file diff --git a/api/src/main/groovy/com/jessebrault/ssg/provider/FileBasedCollectionProvider.groovy b/api/src/main/groovy/com/jessebrault/ssg/provider/FileBasedCollectionProvider.groovy index b5aa37a..b9a4afa 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/provider/FileBasedCollectionProvider.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/provider/FileBasedCollectionProvider.groovy @@ -5,7 +5,6 @@ import groovy.io.FileType import groovy.transform.EqualsAndHashCode import groovy.transform.NullCheck import groovy.transform.PackageScope -import groovy.transform.TupleConstructor import org.jetbrains.annotations.Nullable import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -13,9 +12,8 @@ import org.slf4j.LoggerFactory import java.util.function.BiFunction @PackageScope -@TupleConstructor(includeFields = true, defaults = false) -@NullCheck(includeGenerated = true) -@EqualsAndHashCode(includeFields = true) +@NullCheck +@EqualsAndHashCode(includeFields = true, callSuper = true) final class FileBasedCollectionProvider extends AbstractCollectionProvider { private static final Logger logger = LoggerFactory.getLogger(FileBasedCollectionProvider) @@ -23,6 +21,12 @@ final class FileBasedCollectionProvider extends AbstractCollectionProvider private final File baseDirectory private final BiFunction elementFunction + FileBasedCollectionProvider(File baseDirectory, BiFunction elementFunction) { + super([], []) + this.baseDirectory = baseDirectory + this.elementFunction = elementFunction + } + @Override Collection provide() { if (!this.baseDirectory.isDirectory()) { diff --git a/api/src/main/groovy/com/jessebrault/ssg/provider/SimpleCollectionProvider.groovy b/api/src/main/groovy/com/jessebrault/ssg/provider/SimpleCollectionProvider.groovy index 2721ad8..374807d 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/provider/SimpleCollectionProvider.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/provider/SimpleCollectionProvider.groovy @@ -3,16 +3,19 @@ package com.jessebrault.ssg.provider import groovy.transform.EqualsAndHashCode import groovy.transform.NullCheck import groovy.transform.PackageScope -import groovy.transform.TupleConstructor @PackageScope -@TupleConstructor(defaults = false, includeFields = true) -@NullCheck(includeGenerated = true) -@EqualsAndHashCode(includeFields = true) +@NullCheck +@EqualsAndHashCode(includeFields = true, callSuper = true) final class SimpleCollectionProvider extends AbstractCollectionProvider { private final Collection ts + SimpleCollectionProvider(Collection ts) { + super([], []) + this.ts = ts + } + @Override Collection provide() { this.ts diff --git a/api/src/main/groovy/com/jessebrault/ssg/provider/SupplierBasedCollectionProvider.groovy b/api/src/main/groovy/com/jessebrault/ssg/provider/SupplierBasedCollectionProvider.groovy index 8cdbba9..5c2f0a0 100644 --- a/api/src/main/groovy/com/jessebrault/ssg/provider/SupplierBasedCollectionProvider.groovy +++ b/api/src/main/groovy/com/jessebrault/ssg/provider/SupplierBasedCollectionProvider.groovy @@ -3,18 +3,29 @@ package com.jessebrault.ssg.provider import groovy.transform.EqualsAndHashCode import groovy.transform.NullCheck import groovy.transform.PackageScope -import groovy.transform.TupleConstructor import java.util.function.Supplier @PackageScope -@TupleConstructor(defaults = false, includeFields = true) -@NullCheck(includeGenerated = true) -@EqualsAndHashCode(includeFields = true) +@NullCheck +@EqualsAndHashCode(includeFields = true, callSuper = true) final class SupplierBasedCollectionProvider extends AbstractCollectionProvider { private final Supplier> supplier + SupplierBasedCollectionProvider( + Collection> collectionProviderChildren, + Collection> providerChildren, + Supplier> supplier + ) { + super(collectionProviderChildren, providerChildren) + this.supplier = supplier + } + + SupplierBasedCollectionProvider(Supplier> supplier) { + this([], [], supplier) + } + @Override Collection provide() { this.supplier.get() diff --git a/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegateTests.groovy b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegateTests.groovy new file mode 100644 index 0000000..8f19569 --- /dev/null +++ b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/AbstractBuildDelegateTests.groovy @@ -0,0 +1,97 @@ +package com.jessebrault.ssg.buildscript.dsl + +import com.jessebrault.ssg.SiteSpec +import com.jessebrault.ssg.buildscript.SourceProviders +import com.jessebrault.ssg.buildscript.TypesContainer +import com.jessebrault.ssg.page.Page +import com.jessebrault.ssg.page.PageTypes +import com.jessebrault.ssg.provider.CollectionProvider +import com.jessebrault.ssg.task.TaskFactory +import com.jessebrault.ssg.text.Text +import com.jessebrault.ssg.text.TextTypes +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension + +import java.util.function.Supplier + +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +@ExtendWith(MockitoExtension) +abstract class AbstractBuildDelegateTests { + + protected abstract AbstractBuildDelegate getDelegate() + + @Test + void siteSpecsAdded() { + def d = this.getDelegate() + d.siteSpec { + name = 'test' + } + d.siteSpec { + baseUrl = 'test' + } + def sum = d.getSiteSpecResult() + assertEquals(new SiteSpec('test', 'test'), sum) + } + + @Test + void globalsAdded() { + def d = this.getDelegate() + d.globals { + a = 0 + } + d.globals { + b = 1 + } + def sum = d.getGlobalsResult() + assertEquals([a: 0, b: 1], sum) + } + + @Test + void typesAdded() { + def d = this.getDelegate() + d.types { + textTypes << TextTypes.MARKDOWN + } + d.types { + pageTypes << PageTypes.GSP + } + def sum = d.getTypesResult() + assertTrue(TextTypes.MARKDOWN in sum.textTypes) + assertTrue(PageTypes.GSP in sum.pageTypes) + } + + @Test + void sourcesAdded(@Mock CollectionProvider textsProvider, @Mock CollectionProvider pagesProvider) { + def d = this.getDelegate() + d.providers { + texts(textsProvider) + } + d.providers { + pages(pagesProvider) + } + def sum = d.getSourcesResult(TypesContainer.getEmpty()) + assertTrue(textsProvider in sum.textsProvider) + assertTrue(pagesProvider in sum.pagesProvider) + } + + @Test + void taskFactoriesAdded(@Mock Supplier taskFactorySupplier) { + def d = this.getDelegate() + d.taskFactories { + register('tf0', taskFactorySupplier) + } + d.taskFactories { + register('tf1', taskFactorySupplier) + } + def sum = d.getTaskFactoriesResult(SourceProviders.getEmpty()) + assertEquals(2, sum.size()) + assertTrue(sum.inject(true) { acc, spec -> + acc && spec.supplier == taskFactorySupplier + }) + } + +} diff --git a/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/AllBuildsDelegateTests.groovy b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/AllBuildsDelegateTests.groovy new file mode 100644 index 0000000..6e7b269 --- /dev/null +++ b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/AllBuildsDelegateTests.groovy @@ -0,0 +1,12 @@ +package com.jessebrault.ssg.buildscript.dsl + +import com.jessebrault.ssg.buildscript.Build + +final class AllBuildsDelegateTests extends AbstractBuildDelegateTests { + + @Override + protected AbstractBuildDelegate getDelegate() { + new AllBuildsDelegate() + } + +} diff --git a/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/BuildDelegateTests.groovy b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/BuildDelegateTests.groovy new file mode 100644 index 0000000..f9063ee --- /dev/null +++ b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/BuildDelegateTests.groovy @@ -0,0 +1,12 @@ +package com.jessebrault.ssg.buildscript.dsl + +import com.jessebrault.ssg.buildscript.Build + +final class BuildDelegateTests extends AbstractBuildDelegateTests { + + @Override + protected AbstractBuildDelegate getDelegate() { + new BuildDelegate() + } + +} diff --git a/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegateTests.groovy b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegateTests.groovy new file mode 100644 index 0000000..bb7222f --- /dev/null +++ b/api/src/test/groovy/com/jessebrault/ssg/buildscript/dsl/TaskFactoriesDelegateTests.groovy @@ -0,0 +1,49 @@ +package com.jessebrault.ssg.buildscript.dsl + +import com.jessebrault.ssg.task.TaskFactory +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.function.Executable +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension + +import java.util.function.Consumer +import java.util.function.Supplier + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +@ExtendWith(MockitoExtension) +final class TaskFactoriesDelegateTests { + + @Test + void registerThenConfigure( + @Mock Supplier taskFactorySupplier, + @Mock Consumer taskFactoryConsumer + ) { + def d = new TaskFactoriesDelegate() + d.register('test', taskFactorySupplier) + assertDoesNotThrow({ + d.configure('test', TaskFactory, taskFactoryConsumer) + } as Executable) + def result = d.getResult() + assertTrue(result.containsKey('test')) + assertEquals(taskFactorySupplier, result['test'].supplier) + assertTrue(result['test'].configurators.contains(taskFactoryConsumer)) + } + + @Test + void registerAndConfigure( + @Mock Supplier taskFactorySupplier, + @Mock Consumer taskFactoryConsumer + ) { + def d = new TaskFactoriesDelegate() + d.register('test', taskFactorySupplier, taskFactoryConsumer) + def result = d.getResult() + assertTrue(result.containsKey('test')) + assertEquals(taskFactorySupplier, result['test'].supplier) + assertTrue(result['test'].configurators.contains(taskFactoryConsumer)) + } + +}