Major refactor to renderers.
This commit is contained in:
parent
79c0d158f3
commit
c5ac81055c
@ -25,6 +25,8 @@ dependencies {
|
||||
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
|
||||
implementation 'org.slf4j:slf4j-api:1.7.36'
|
||||
|
||||
testFixturesImplementation 'org.slf4j:slf4j-api:1.7.36'
|
||||
|
||||
/**
|
||||
* TESTING
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.buildscript.GroovyBuildScriptRunner
|
||||
import com.jessebrault.ssg.output.OutputPage
|
||||
import com.jessebrault.ssg.task.Output
|
||||
import com.jessebrault.ssg.part.GspPartRenderer
|
||||
import com.jessebrault.ssg.part.PartFilePartsProvider
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
@ -86,10 +86,10 @@ abstract class AbstractBuildCommand extends AbstractSubCommand {
|
||||
logger.error(it.message)
|
||||
}
|
||||
} else {
|
||||
result.v2.each { OutputPage outputPage ->
|
||||
def target = new File(it.outDir, outputPage.path)
|
||||
result.v2.each { Output output ->
|
||||
def target = new File(it.outDir, output.meta.targetPath)
|
||||
target.createParentDirectories()
|
||||
target.write(outputPage.content)
|
||||
target.write(output.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.output.OutputPage
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.specialpage.SpecialPage
|
||||
import com.jessebrault.ssg.task.Output
|
||||
import com.jessebrault.ssg.task.OutputMeta
|
||||
import com.jessebrault.ssg.task.OutputMetaMap
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
@ -22,7 +27,7 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||
private static final Marker exit = MarkerFactory.getMarker('EXIT')
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, Collection<OutputPage>> generate(Build build) {
|
||||
Tuple2<Collection<Diagnostic>, Collection<Output>> generate(Build build) {
|
||||
logger.trace(enter, 'build: {}', build)
|
||||
logger.info('processing build with name: {}', build.name)
|
||||
|
||||
@ -39,18 +44,29 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||
|
||||
def globals = build.globals
|
||||
Collection<Diagnostic> diagnostics = []
|
||||
Collection<OutputPage> generatedPages = []
|
||||
Collection<Output> generatedPages = []
|
||||
|
||||
Map<Text, OutputMeta> textOutputTasks = texts.collectEntries {
|
||||
[(it): new OutputMeta(it.path, stripExtension(it.path) + '.html')]
|
||||
}
|
||||
Map<SpecialPage, OutputMeta> specialPageOutputTasks = specialPages.collectEntries {
|
||||
[(it): new OutputMeta(it.path, stripExtension(it.path) + '.html')]
|
||||
}
|
||||
|
||||
def textOutputMetas = textOutputTasks.values() as ArrayList
|
||||
def specialPageOutputMetas = specialPageOutputTasks.values() as ArrayList
|
||||
def outputMetaMap = new OutputMetaMap([*textOutputMetas, *specialPageOutputMetas])
|
||||
|
||||
// Generate pages from each text, but only those that have a 'template' frontMatter field with a valid value
|
||||
texts.each {
|
||||
logger.trace(enter, 'text: {}', it)
|
||||
logger.info('processing text: {}', it.path)
|
||||
textOutputTasks.each { text, outputMeta ->
|
||||
logger.trace(enter, 'text: {}, outputMeta: {}', text, outputMeta)
|
||||
logger.info('processing text: {}', text.path)
|
||||
|
||||
// Extract frontMatter from text
|
||||
def frontMatterResult = it.type.frontMatterGetter.get(it)
|
||||
def frontMatterResult = text.type.frontMatterGetter.get(text)
|
||||
FrontMatter frontMatter
|
||||
if (frontMatterResult.v1.size() > 0) {
|
||||
logger.debug('diagnostics for getting frontMatter for {}: {}', it.path, frontMatterResult.v1)
|
||||
logger.debug('diagnostics for getting frontMatter for {}: {}', text.path, frontMatterResult.v1)
|
||||
diagnostics.addAll(frontMatterResult.v1)
|
||||
logger.trace(exit, '')
|
||||
return
|
||||
@ -62,28 +78,30 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||
// Find the appropriate template from the frontMatter
|
||||
def desiredTemplate = frontMatter.find('template')
|
||||
if (desiredTemplate.isEmpty()) {
|
||||
logger.info('{} has no \'template\' key in its frontMatter; skipping generation', it)
|
||||
logger.info('{} has no \'template\' key in its frontMatter; skipping generation', text)
|
||||
return
|
||||
}
|
||||
def template = templates.find { it.path == desiredTemplate.get() }
|
||||
if (template == null) {
|
||||
diagnostics << new Diagnostic('in textFile' + it.path + ' frontMatter.template references an unknown template: ' + desiredTemplate, null)
|
||||
diagnostics << new Diagnostic('in textFile' + text.path + ' frontMatter.template references an unknown template: ' + desiredTemplate, null)
|
||||
logger.trace(exit, '')
|
||||
return
|
||||
}
|
||||
logger.debug('found template: {}', template)
|
||||
|
||||
def targetPath = stripExtension(it.path) + '.html'
|
||||
|
||||
// Render the template using the result of rendering the text earlier
|
||||
def templateRenderResult = template.type.renderer.render(
|
||||
template,
|
||||
frontMatter,
|
||||
it,
|
||||
parts,
|
||||
siteSpec,
|
||||
globals,
|
||||
targetPath
|
||||
text,
|
||||
new RenderContext(
|
||||
config,
|
||||
siteSpec,
|
||||
globals,
|
||||
texts,
|
||||
parts,
|
||||
outputMeta.sourcePath,
|
||||
outputMeta.targetPath
|
||||
)
|
||||
)
|
||||
String renderedTemplate
|
||||
if (templateRenderResult.v1.size() > 0) {
|
||||
@ -95,21 +113,25 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||
}
|
||||
|
||||
// Create a GeneratedPage
|
||||
generatedPages << new OutputPage(targetPath, renderedTemplate)
|
||||
generatedPages << new Output(outputMeta, renderedTemplate)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate special pages
|
||||
specialPages.each {
|
||||
logger.info('processing specialPage: {}', it.path)
|
||||
specialPageOutputTasks.each { specialPage, outputMeta ->
|
||||
logger.info('processing specialPage: {}', specialPage.path)
|
||||
|
||||
def targetPath = stripExtension(it.path) + '.html'
|
||||
def specialPageRenderResult = it.type.renderer.render(
|
||||
it,
|
||||
texts,
|
||||
parts,
|
||||
siteSpec,
|
||||
globals,
|
||||
targetPath
|
||||
def specialPageRenderResult = specialPage.type.renderer.render(
|
||||
specialPage,
|
||||
new RenderContext(
|
||||
config,
|
||||
siteSpec,
|
||||
globals,
|
||||
texts,
|
||||
parts,
|
||||
outputMeta.sourcePath,
|
||||
outputMeta.targetPath
|
||||
)
|
||||
)
|
||||
String renderedSpecialPage
|
||||
if (specialPageRenderResult.v1.size() > 0) {
|
||||
@ -121,7 +143,8 @@ class SimpleStaticSiteGenerator implements StaticSiteGenerator {
|
||||
}
|
||||
|
||||
// Create a GeneratedPage
|
||||
generatedPages << new OutputPage(targetPath, renderedSpecialPage)
|
||||
generatedPages << new Output(outputMeta, renderedSpecialPage)
|
||||
return
|
||||
}
|
||||
|
||||
logger.trace(exit, '\n\tdiagnostics: {}\n\tgeneratedPages: {}', diagnostics, generatedPages)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.jessebrault.ssg
|
||||
|
||||
import com.jessebrault.ssg.output.OutputPage
|
||||
import com.jessebrault.ssg.task.Output
|
||||
|
||||
interface StaticSiteGenerator {
|
||||
Tuple2<Collection<Diagnostic>, Collection<OutputPage>> generate(Build build)
|
||||
Tuple2<Collection<Diagnostic>, Collection<Output>> generate(Build build)
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
package com.jessebrault.ssg.dsl
|
||||
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import com.jessebrault.ssg.url.PathBasedUrlBuilder
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.SimpleType
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
final class StandardDslMap {
|
||||
|
||||
@NullCheck(includeGenerated = true)
|
||||
static final class Builder {
|
||||
|
||||
private final Map custom = [:]
|
||||
|
||||
String loggerName = ''
|
||||
Closure onDiagnostics = { }
|
||||
Text text = null
|
||||
|
||||
void putCustom(key, value) {
|
||||
this.custom.put(key, value)
|
||||
}
|
||||
|
||||
void putAllCustom(Map m) {
|
||||
this.custom.putAll(m)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static Map get(
|
||||
RenderContext context,
|
||||
@DelegatesTo(value = Builder, strategy = Closure.DELEGATE_FIRST)
|
||||
@ClosureParams(
|
||||
value = SimpleType,
|
||||
options = ['com.jessebrault.ssg.dsl.StandardDslMap.Builder']
|
||||
)
|
||||
Closure builderClosure
|
||||
) {
|
||||
def b = new Builder()
|
||||
builderClosure.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
builderClosure.delegate = b
|
||||
builderClosure(b)
|
||||
|
||||
[:].tap {
|
||||
it.globals = context.globals
|
||||
it.logger = LoggerFactory.getLogger(b.loggerName)
|
||||
it.parts = new EmbeddablePartsMap(
|
||||
context.parts,
|
||||
context,
|
||||
b.onDiagnostics,
|
||||
b.text
|
||||
)
|
||||
it.siteSpec = context.siteSpec
|
||||
it.sourcePath = context.sourcePath
|
||||
it.targetPath = context.targetPath
|
||||
it.text = b.text ? new EmbeddableText(
|
||||
b.text,
|
||||
context.globals,
|
||||
b.onDiagnostics
|
||||
) : null
|
||||
it.texts = new EmbeddableTextsCollection(
|
||||
context.texts,
|
||||
context.globals,
|
||||
b.onDiagnostics
|
||||
)
|
||||
it.urlBuilder = new PathBasedUrlBuilder(
|
||||
context.targetPath,
|
||||
context.siteSpec.baseUrl
|
||||
)
|
||||
|
||||
it.putAll(b.custom)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.jessebrault.ssg.input
|
||||
|
||||
interface InputPage {
|
||||
String getPath()
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package com.jessebrault.ssg.output
|
||||
|
||||
import com.jessebrault.ssg.input.InputPage
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
|
||||
import static com.jessebrault.ssg.util.ExtensionsUtil.stripExtension
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
final class OutputPage {
|
||||
|
||||
@Deprecated
|
||||
static OutputPage of(InputPage inputFile, String extension, String content) {
|
||||
new OutputPage(stripExtension(inputFile.path) + extension, content)
|
||||
}
|
||||
|
||||
final String path
|
||||
final String content
|
||||
|
||||
OutputPage(String path, String content) {
|
||||
this.path = path
|
||||
this.content = content
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"GeneratedPage(path: ${ this.path })"
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +1,42 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
@NullCheck
|
||||
import static java.util.Objects.requireNonNull
|
||||
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddablePart {
|
||||
|
||||
private final Part part
|
||||
private final SiteSpec siteSpec
|
||||
private final Map globals
|
||||
private final RenderContext context
|
||||
private final Closure onDiagnostics
|
||||
|
||||
@Nullable
|
||||
private final EmbeddableText text
|
||||
private final Text text
|
||||
|
||||
private final Collection<Part> allParts
|
||||
private final String path
|
||||
private final String targetPath
|
||||
EmbeddablePart(
|
||||
Part part,
|
||||
RenderContext context,
|
||||
Closure onDiagnostics,
|
||||
@Nullable Text text
|
||||
) {
|
||||
this.part = requireNonNull(part)
|
||||
this.context = requireNonNull(context)
|
||||
this.onDiagnostics = requireNonNull(onDiagnostics)
|
||||
this.text = text
|
||||
}
|
||||
|
||||
String render(Map binding = [:]) {
|
||||
def result = part.type.renderer.render(
|
||||
this.part,
|
||||
binding,
|
||||
this.siteSpec,
|
||||
this.globals,
|
||||
this.text,
|
||||
this.allParts,
|
||||
this.path,
|
||||
this.targetPath
|
||||
this.context,
|
||||
this.text
|
||||
)
|
||||
if (result.v1.size() > 0) {
|
||||
this.onDiagnostics.call(result.v1)
|
||||
@ -45,8 +48,7 @@ class EmbeddablePart {
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"EmbeddablePart(part: ${ this.part }, globals: ${ this.globals }, path: ${ this.path }, " +
|
||||
"targetPath: ${ this.targetPath })"
|
||||
"EmbeddablePart(part: ${ this.part })"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
import static java.util.Objects.requireNonNull
|
||||
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddablePartsMap {
|
||||
|
||||
@ -13,21 +15,15 @@ class EmbeddablePartsMap {
|
||||
|
||||
EmbeddablePartsMap(
|
||||
Collection<Part> parts,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
RenderContext context,
|
||||
Closure onDiagnostics,
|
||||
@Nullable EmbeddableText text = null,
|
||||
String path,
|
||||
String targetPath
|
||||
@Nullable Text text = null
|
||||
) {
|
||||
Objects.requireNonNull(parts)
|
||||
Objects.requireNonNull(siteSpec)
|
||||
Objects.requireNonNull(globals)
|
||||
Objects.requireNonNull(onDiagnostics)
|
||||
Objects.requireNonNull(path)
|
||||
Objects.requireNonNull(targetPath)
|
||||
requireNonNull(parts)
|
||||
requireNonNull(context)
|
||||
requireNonNull(onDiagnostics)
|
||||
parts.each {
|
||||
this.put(it.path, new EmbeddablePart(it, siteSpec, globals, onDiagnostics, text, parts, path, targetPath))
|
||||
this.put(it.path, new EmbeddablePart(it, context, onDiagnostics, text))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,14 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.tagbuilder.DynamicTagBuilder
|
||||
import com.jessebrault.ssg.dsl.StandardDslMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.url.PathBasedUrlBuilder
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@EqualsAndHashCode
|
||||
class GspPartRenderer implements PartRenderer {
|
||||
@ -20,46 +19,27 @@ class GspPartRenderer implements PartRenderer {
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Part part,
|
||||
Map binding,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
@Nullable EmbeddableText text = null,
|
||||
Collection<Part> allParts,
|
||||
String path,
|
||||
String targetPath
|
||||
RenderContext context,
|
||||
@Nullable Text text
|
||||
) {
|
||||
Objects.requireNonNull(part)
|
||||
Objects.requireNonNull(binding)
|
||||
Objects.requireNonNull(siteSpec)
|
||||
Objects.requireNonNull(globals)
|
||||
Objects.requireNonNull(allParts)
|
||||
Objects.requireNonNull(path)
|
||||
Objects.requireNonNull(targetPath)
|
||||
def embeddedPartDiagnostics = []
|
||||
Objects.requireNonNull(context)
|
||||
def diagnostics = []
|
||||
try {
|
||||
def result = engine.createTemplate(part.text).make([
|
||||
binding: binding,
|
||||
globals: globals,
|
||||
logger: LoggerFactory.getLogger("Part(${ part.path })"),
|
||||
parts: new EmbeddablePartsMap(
|
||||
allParts,
|
||||
siteSpec,
|
||||
globals,
|
||||
embeddedPartDiagnostics.&addAll,
|
||||
text,
|
||||
path,
|
||||
targetPath
|
||||
),
|
||||
path: path,
|
||||
siteSpec: siteSpec,
|
||||
tagBuilder: new DynamicTagBuilder(),
|
||||
targetPath: targetPath,
|
||||
text: text,
|
||||
urlBuilder: new PathBasedUrlBuilder(targetPath, siteSpec.baseUrl)
|
||||
])
|
||||
new Tuple2<>(embeddedPartDiagnostics, result.toString())
|
||||
def dslMap = StandardDslMap.get(context) {
|
||||
it.putCustom('binding', binding)
|
||||
it.loggerName = "GspPart(${ part.path })"
|
||||
it.onDiagnostics = diagnostics.&addAll
|
||||
if (text) {
|
||||
it.text = text
|
||||
}
|
||||
}
|
||||
def result = engine.createTemplate(part.text).make(dslMap)
|
||||
new Tuple2<>(diagnostics, result.toString())
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>(
|
||||
[*embeddedPartDiagnostics, new Diagnostic(
|
||||
[*diagnostics, new Diagnostic(
|
||||
"An exception occurred while rendering part ${ part.path }:\n${ e }",
|
||||
e
|
||||
)],
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
interface PartRenderer {
|
||||
@ -10,12 +10,8 @@ interface PartRenderer {
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Part part,
|
||||
Map binding,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
@Nullable EmbeddableText text,
|
||||
Collection<Part> allParts,
|
||||
String path,
|
||||
String targetPath
|
||||
RenderContext context,
|
||||
@Nullable Text text
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package com.jessebrault.ssg.renderer
|
||||
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode
|
||||
final class RenderContext {
|
||||
final Config config
|
||||
final SiteSpec siteSpec
|
||||
final Map globals
|
||||
final Collection<Text> texts
|
||||
final Collection<Part> parts
|
||||
final String sourcePath
|
||||
final String targetPath
|
||||
}
|
@ -1,18 +1,12 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.tagbuilder.DynamicTagBuilder
|
||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import com.jessebrault.ssg.url.PathBasedUrlBuilder
|
||||
import com.jessebrault.ssg.dsl.StandardDslMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
@ -23,35 +17,24 @@ class GspSpecialPageRenderer implements SpecialPageRenderer {
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
SpecialPage specialPage,
|
||||
Collection<Text> texts,
|
||||
Collection<Part> parts,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
String targetPath
|
||||
RenderContext context
|
||||
) {
|
||||
Collection<Diagnostic> diagnostics = []
|
||||
def diagnostics = []
|
||||
try {
|
||||
def result = engine.createTemplate(specialPage.text).make([
|
||||
globals: globals,
|
||||
logger: LoggerFactory.getLogger("SpecialPage(${ specialPage.path })"),
|
||||
parts: new EmbeddablePartsMap(
|
||||
parts,
|
||||
siteSpec,
|
||||
globals,
|
||||
diagnostics.&addAll,
|
||||
specialPage.path,
|
||||
targetPath
|
||||
),
|
||||
path: specialPage.path,
|
||||
siteSpec: siteSpec,
|
||||
tagBuilder: new DynamicTagBuilder(),
|
||||
targetPath: targetPath,
|
||||
texts: new EmbeddableTextsCollection(texts, globals, diagnostics.&addAll),
|
||||
urlBuilder: new PathBasedUrlBuilder(targetPath, siteSpec.baseUrl)
|
||||
])
|
||||
def dslMap = StandardDslMap.get(context) {
|
||||
it.loggerName = "GspSpecialPage(${ specialPage.path })"
|
||||
it.onDiagnostics = diagnostics.&addAll
|
||||
}
|
||||
def result = engine.createTemplate(specialPage.text).make(dslMap)
|
||||
new Tuple2<>(diagnostics, result.toString())
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>([*diagnostics, new Diagnostic("An exception occurred while rendering specialPage ${ specialPage.path }:\n${ e }", e)], '')
|
||||
new Tuple2<>(
|
||||
[*diagnostics, new Diagnostic(
|
||||
"An exception occurred while rendering specialPage ${ specialPage.path }:\n${ e }",
|
||||
e
|
||||
)],
|
||||
''
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.input.InputPage
|
||||
import com.jessebrault.ssg.task.Input
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
@ -8,7 +8,7 @@ import groovy.transform.TupleConstructor
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class SpecialPage implements InputPage {
|
||||
class SpecialPage implements Input {
|
||||
|
||||
String text
|
||||
String path
|
||||
|
@ -3,17 +3,14 @@ package com.jessebrault.ssg.specialpage
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
|
||||
interface SpecialPageRenderer {
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
SpecialPage specialPage,
|
||||
Collection<Text> texts,
|
||||
Collection <Part> parts,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
String targetPath
|
||||
RenderContext context
|
||||
)
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface Input {
|
||||
String getPath()
|
||||
}
|
20
lib/src/main/groovy/com/jessebrault/ssg/task/Output.groovy
Normal file
20
lib/src/main/groovy/com/jessebrault/ssg/task/Output.groovy
Normal file
@ -0,0 +1,20 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
final class Output {
|
||||
|
||||
final OutputMeta meta
|
||||
final String content
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"Output(meta: ${ this.meta })"
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
final class OutputMeta {
|
||||
|
||||
final String sourcePath
|
||||
final String targetPath
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"OutputMeta(sourcePath: ${ sourcePath }, targetPath: ${ targetPath })"
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
final class OutputMetaMap {
|
||||
|
||||
@Delegate
|
||||
private final Map<String, OutputMeta> map = [:]
|
||||
|
||||
OutputMetaMap(Collection<OutputMeta> outputMetas) {
|
||||
outputMetas.each {
|
||||
this.put(it.sourcePath, it)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"OutputMetaMap(map: ${ this.map })"
|
||||
}
|
||||
|
||||
}
|
6
lib/src/main/groovy/com/jessebrault/ssg/task/Task.groovy
Normal file
6
lib/src/main/groovy/com/jessebrault/ssg/task/Task.groovy
Normal file
@ -0,0 +1,6 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
interface Task {
|
||||
Output getOutput()
|
||||
OutputMeta getOutputMeta()
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import groovy.transform.TupleConstructor
|
||||
import groovy.transform.builder.Builder
|
||||
|
||||
@Builder
|
||||
@TupleConstructor(defaults = false)
|
||||
final class TaskContext {
|
||||
|
||||
final Config config
|
||||
final SiteSpec siteSpec
|
||||
final Collection<OutputMeta> outputMetas
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
"TaskContext(config: ${ this.config }, siteSpec: ${ this.siteSpec }, outputMetas: ${ this.outputMetas })"
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.jessebrault.ssg.task
|
||||
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
interface TaskFactory {
|
||||
@Nullable Task getTask(Input input, TaskContext context)
|
||||
}
|
@ -1,19 +1,13 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.tagbuilder.DynamicTagBuilder
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import com.jessebrault.ssg.dsl.StandardDslMap
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import com.jessebrault.ssg.url.PathBasedUrlBuilder
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.TemplateEngine
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
@ -24,32 +18,26 @@ class GspTemplateRenderer implements TemplateRenderer {
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Template template,
|
||||
@Deprecated
|
||||
FrontMatter frontMatter,
|
||||
Text text,
|
||||
Collection<Part> parts,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
String targetPath
|
||||
RenderContext context
|
||||
) {
|
||||
def diagnostics = []
|
||||
try {
|
||||
def embeddableText = new EmbeddableText(text, globals, diagnostics.&addAll)
|
||||
def result = engine.createTemplate(template.text).make([
|
||||
frontMatter: frontMatter,
|
||||
globals: globals,
|
||||
logger: LoggerFactory.getLogger("Template(${ template.path })"),
|
||||
parts: new EmbeddablePartsMap(parts, siteSpec, globals, diagnostics.&addAll, embeddableText, text.path, targetPath),
|
||||
path: text.path,
|
||||
siteSpec: siteSpec,
|
||||
tagBuilder: new DynamicTagBuilder(),
|
||||
targetPath: targetPath,
|
||||
text: embeddableText,
|
||||
urlBuilder: new PathBasedUrlBuilder(targetPath, siteSpec.baseUrl)
|
||||
])
|
||||
def dslMap = StandardDslMap.get(context) {
|
||||
it.loggerName = "GspTemplate(${ template.path })"
|
||||
it.onDiagnostics = diagnostics.&addAll
|
||||
it.text = text
|
||||
}
|
||||
def result = engine.createTemplate(template.text).make(dslMap)
|
||||
new Tuple2<>(diagnostics, result.toString())
|
||||
} catch (Exception e) {
|
||||
new Tuple2<>([*diagnostics, new Diagnostic("An exception occurred while rendering Template ${ template.path }:\n${ e }", e)], '')
|
||||
new Tuple2<>(
|
||||
[*diagnostics, new Diagnostic(
|
||||
"An exception occurred while rendering Template ${ template.path }:\n${ e }",
|
||||
e
|
||||
)],
|
||||
''
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,15 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
|
||||
interface TemplateRenderer {
|
||||
|
||||
/**
|
||||
* TODO: get rid of frontMatter param since we can obtain it from the text
|
||||
*/
|
||||
Tuple2<Collection<Diagnostic>, String> render(
|
||||
Template template,
|
||||
@Deprecated
|
||||
FrontMatter frontMatter,
|
||||
Text text,
|
||||
Collection<Part> parts,
|
||||
SiteSpec siteSpec,
|
||||
Map globals,
|
||||
String targetPath
|
||||
RenderContext context
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@TupleConstructor(includeFields = true, defaults = false)
|
||||
@NullCheck
|
||||
@NullCheck(includeGenerated = true)
|
||||
@EqualsAndHashCode(includeFields = true)
|
||||
class EmbeddableText {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.jessebrault.ssg.text
|
||||
|
||||
import com.jessebrault.ssg.input.InputPage
|
||||
import com.jessebrault.ssg.task.Input
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.NullCheck
|
||||
import groovy.transform.TupleConstructor
|
||||
@ -8,7 +8,7 @@ import groovy.transform.TupleConstructor
|
||||
@TupleConstructor(defaults = false)
|
||||
@NullCheck
|
||||
@EqualsAndHashCode
|
||||
class Text implements InputPage {
|
||||
class Text implements Input {
|
||||
|
||||
String text
|
||||
String path
|
||||
|
@ -71,7 +71,7 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
||||
assertTrue(result.v2.size() == 1)
|
||||
|
||||
def p0 = result.v2[0]
|
||||
assertEquals('test.html', p0.path)
|
||||
assertEquals('test.html', p0.meta.targetPath)
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.content)
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
||||
assertTrue(result.v2.size() == 1)
|
||||
|
||||
def p0 = result.v2[0]
|
||||
assertEquals('nested/nested.html', p0.path)
|
||||
assertEquals('nested/nested.html', p0.meta.targetPath)
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', p0.content)
|
||||
}
|
||||
|
||||
@ -107,11 +107,11 @@ class SimpleStaticSiteGeneratorIntegrationTests {
|
||||
assertEmptyDiagnostics(result)
|
||||
assertEquals(2, result.v2.size())
|
||||
|
||||
def testPage = result.v2.find { it.path == 'test.html' }
|
||||
def testPage = result.v2.find { it.meta.targetPath == 'test.html' }
|
||||
assertNotNull(testPage)
|
||||
assertEquals('2', testPage.content)
|
||||
|
||||
def specialPage = result.v2.find { it.path == 'special.html' }
|
||||
def specialPage = result.v2.find { it.meta.targetPath == 'special.html' }
|
||||
assertNotNull(specialPage)
|
||||
assertEquals('<p>Hello, World!</p>\n', specialPage.content)
|
||||
}
|
||||
|
@ -1,224 +1,58 @@
|
||||
package com.jessebrault.ssg.part
|
||||
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.text.EmbeddableText
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslConsumerTests
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockedStatic
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertDiagnosticException
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.getDiagnosticsMessageSupplier
|
||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableText
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
import static org.mockito.ArgumentMatchers.anyString
|
||||
import static org.mockito.Mockito.mockStatic
|
||||
import static org.mockito.Mockito.verify
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
class GspPartRendererTests {
|
||||
class GspPartRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private final PartRenderer renderer = new GspPartRenderer()
|
||||
|
||||
@Test
|
||||
void rendersWithNoBindingOrGlobals() {
|
||||
def part = new Part('', null, 'Hello, World!')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
private Tuple2<Collection<Diagnostic>, String> doRender(
|
||||
String scriptlet,
|
||||
RenderContext context,
|
||||
Map binding = [:],
|
||||
Text text = null
|
||||
) {
|
||||
this.renderer.render(
|
||||
new Part('', new PartType([], this.renderer), scriptlet),
|
||||
binding,
|
||||
context,
|
||||
text
|
||||
)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context) {
|
||||
this.doRender(scriptlet, context)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersWithBinding() {
|
||||
def part = new Part('', null, "<%= binding['greeting'] %>")
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[greeting: 'Hello, World!'],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
this.checkResult(
|
||||
'Hello, World!',
|
||||
this.doRender('<%= binding.greeting %>', getRenderContext(), [greeting: 'Hello, World!'])
|
||||
)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersWithGlobals() {
|
||||
def part = new Part(null, null, "<%= globals['greeting'] %>")
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[greeting: 'Hello, World!'],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
)
|
||||
assertTrue(r.v1.size() == 0)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void textAvailable() {
|
||||
def part = new Part('', null, '<%= text.render() %>')
|
||||
def textDiagnostics = []
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
this.checkResult('Hello, World!', this.renderer.render(
|
||||
new Part('', new PartType([], this.renderer), '<%= text.render() %>'),
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
new EmbeddableText(renderableText('Hello, World!'), [:], textDiagnostics.&addAll),
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
)
|
||||
assertTrue(textDiagnostics.isEmpty())
|
||||
assertTrue(r.v1.isEmpty())
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagBuilderAvailable() {
|
||||
def part = new Part('', null, '<%= tagBuilder.test() %>')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
)
|
||||
assertTrue(r.v1.isEmpty())
|
||||
assertEquals('<test />', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void allPartsAvailable() {
|
||||
def partType = new PartType(['.gsp'], this.renderer)
|
||||
def part0 = new Part('part0.gsp', partType, '<%= parts["part1.gsp"].render() %>')
|
||||
def part1 = new Part('part1.gsp', partType, 'Hello, World!')
|
||||
def r = this.renderer.render(
|
||||
part0,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part0, part1],
|
||||
'',
|
||||
''
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathAvailableIfPresent() {
|
||||
def part = new Part('', null, '<%= path %>')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'test.md',
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('test.md', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlBuilderAvailable() {
|
||||
def part = new Part('', null, '<%= urlBuilder.relative("images/test.jpg") %>')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
'test/test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('../images/test.jpg', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetPathAvailable() {
|
||||
def part = new Part('', null, '<%= targetPath %>')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
'test/test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('test/test.html', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void siteSpecBaseUrlAvailable() {
|
||||
def part = new Part('', null, '<%= siteSpec.baseUrl %>')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', 'https://test.com'),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('https://test.com', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void loggerAvailable(@Mock Logger logger) {
|
||||
try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory)) {
|
||||
loggerFactory.when { LoggerFactory.getLogger(anyString()) }
|
||||
.thenReturn(logger)
|
||||
def part = new Part('', null, '<% logger.info "Hello, World!" %>')
|
||||
def r = this.renderer.render(
|
||||
part,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[part],
|
||||
'',
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
verify(logger).info('Hello, World!')
|
||||
}
|
||||
getRenderContext(),
|
||||
renderableText('Hello, World!')
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -228,16 +62,16 @@ class GspPartRendererTests {
|
||||
new PartType([], this.renderer),
|
||||
'<% throw new RuntimeException() %>'
|
||||
)
|
||||
def callerPart = new Part('caller.gsp', null, '<% parts["nestedProblem.gsp"].render() %>')
|
||||
def callerPart = new Part(
|
||||
'caller.gsp',
|
||||
null,
|
||||
'<% parts["nestedProblem.gsp"].render() %>'
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
callerPart,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[callerPart, nestedProblemPart],
|
||||
'',
|
||||
''
|
||||
getRenderContext(parts: [callerPart, nestedProblemPart]),
|
||||
null
|
||||
)
|
||||
assertEquals(1, r.v1.size())
|
||||
assertDiagnosticException(RuntimeException, r.v1[0])
|
||||
@ -249,7 +83,7 @@ class GspPartRendererTests {
|
||||
def nestedProblemPart = new Part(
|
||||
'nestedProblem.gsp',
|
||||
new PartType([], this.renderer),
|
||||
'<% throw new RuntimeException() %>'
|
||||
'<% throw new RuntimeException("nested problem exception") %>'
|
||||
)
|
||||
def callerPart = new Part(
|
||||
'caller.gsp',
|
||||
@ -259,15 +93,17 @@ class GspPartRendererTests {
|
||||
def r = this.renderer.render(
|
||||
callerPart,
|
||||
[:],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
null,
|
||||
[callerPart, nestedProblemPart],
|
||||
'',
|
||||
''
|
||||
getRenderContext(parts: [callerPart, nestedProblemPart]),
|
||||
null
|
||||
)
|
||||
assertEquals(1, r.v1.size())
|
||||
assertDiagnosticException(RuntimeException, r.v1[0])
|
||||
assertDiagnosticException(RuntimeException, r.v1[0]) { e ->
|
||||
assertEquals('nested problem exception', e.message, {
|
||||
def w = new StringWriter()
|
||||
e.printStackTrace(new PrintWriter(w))
|
||||
w.toString()
|
||||
})
|
||||
}
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
|
@ -1,242 +1,22 @@
|
||||
package com.jessebrault.ssg.specialpage
|
||||
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.part.PartRenderer
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
import com.jessebrault.ssg.text.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslConsumerTests
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockedStatic
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.mockito.ArgumentMatchers.any
|
||||
import static org.mockito.ArgumentMatchers.anyString
|
||||
import static org.mockito.ArgumentMatchers.argThat
|
||||
import static org.mockito.Mockito.mockStatic
|
||||
import static org.mockito.Mockito.verify
|
||||
import static org.mockito.Mockito.when
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
class GspSpecialPageRendererTests {
|
||||
class GspSpecialPageRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private final SpecialPageRenderer renderer = new GspSpecialPageRenderer()
|
||||
|
||||
@Test
|
||||
void rendersGlobal() {
|
||||
def specialPage = new SpecialPage("<%= globals['greeting'] %>", 'test.gsp', null)
|
||||
def globals = [greeting: 'Hello, World!']
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
globals,
|
||||
''
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context) {
|
||||
this.renderer.render(
|
||||
new SpecialPage(scriptlet, '', new SpecialPageType([], this.renderer)),
|
||||
context
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersPartWithNoBinding(@Mock PartRenderer partRenderer) {
|
||||
when(partRenderer.render(any(), any(), any(), any(), any(), any(), any(), any()))
|
||||
.thenReturn(new Tuple2<>([], 'Hello, World!'))
|
||||
def partType = new PartType([], partRenderer)
|
||||
def part = new Part('test', partType , '')
|
||||
|
||||
def specialPage = new SpecialPage("<%= parts['test'].render() %>", 'test.gsp', null)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[part],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersPartWithBinding(@Mock PartRenderer partRenderer) {
|
||||
when(partRenderer.render(
|
||||
any(),
|
||||
argThat { Map m -> m.get('greeting') == 'Hello, World!'},
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)).thenReturn(new Tuple2<>([], 'Hello, World!'))
|
||||
def partType = new PartType([], partRenderer)
|
||||
def part = new Part('test', partType, '')
|
||||
|
||||
def specialPage = new SpecialPage(
|
||||
"<%= parts['test'].render([greeting: 'Hello, World!'])",
|
||||
'test.gsp',
|
||||
null
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[part],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersText(@Mock TextRenderer textRenderer, @Mock FrontMatterGetter frontMatterGetter) {
|
||||
when(textRenderer.render(any(), any()))
|
||||
.thenReturn(new Tuple2<>([], '<p><strong>Hello, World!</strong></p>\n'))
|
||||
def textType = new TextType([], textRenderer, frontMatterGetter, new MarkdownExcerptGetter())
|
||||
def text = new Text('', 'test', textType)
|
||||
|
||||
def specialPage = new SpecialPage(
|
||||
"<%= texts.find { it.path == 'test' }.render() %>",
|
||||
'test.gsp',
|
||||
null
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[text],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('<p><strong>Hello, World!</strong></p>\n', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagBuilderAvailable() {
|
||||
def specialPage = new SpecialPage('<%= tagBuilder.test() %>', 'test.gsp', null)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('<test />', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathAvailable() {
|
||||
def specialPage = new SpecialPage('<%= path %>', 'test.gsp', null)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('test.gsp', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlBuilderAvailable() {
|
||||
def specialPage = new SpecialPage(
|
||||
'<%= urlBuilder.relative("images/test.jpg") %>',
|
||||
'test.gsp',
|
||||
null
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
'test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('images/test.jpg', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlBuilderIsRelativeToTargetPath() {
|
||||
def specialPage = new SpecialPage(
|
||||
'<%= urlBuilder.relative("images/test.jpg") %>',
|
||||
'',
|
||||
null
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
'test/test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('../images/test.jpg', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetPathAvailable() {
|
||||
def specialPage = new SpecialPage(
|
||||
'<%= targetPath %>',
|
||||
'',
|
||||
null
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
'test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('test.html', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void siteSpecBaseUrlAvailable() {
|
||||
def specialPage = new SpecialPage(
|
||||
'<%= siteSpec.baseUrl %>',
|
||||
'',
|
||||
null
|
||||
)
|
||||
def r = this.renderer.render(
|
||||
specialPage,
|
||||
[],
|
||||
[],
|
||||
new SiteSpec('', 'https://test.com'),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('https://test.com', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void loggerAvailable(@Mock Logger logger) {
|
||||
try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory)) {
|
||||
loggerFactory.when { LoggerFactory.getLogger(anyString()) }
|
||||
.thenReturn(logger)
|
||||
def specialPage = new SpecialPage('<% logger.info "Hello, World!" %>', '', null)
|
||||
def r = this.renderer.render(
|
||||
specialPage, [], [], new SiteSpec('', ''), [:], ''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
verify(logger).info('Hello, World!')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,274 +1,47 @@
|
||||
package com.jessebrault.ssg.template
|
||||
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.part.PartRenderer
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
import com.jessebrault.ssg.text.FrontMatter
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.dsl.StandardDslConsumerTests
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.text.Text
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockedStatic
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.getDiagnosticsMessageSupplier
|
||||
import static com.jessebrault.ssg.text.TextMocks.*
|
||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||
import static com.jessebrault.ssg.text.TextMocks.blankText
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableText
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
import static org.mockito.ArgumentMatchers.any
|
||||
import static org.mockito.ArgumentMatchers.anyString
|
||||
import static org.mockito.ArgumentMatchers.argThat
|
||||
import static org.mockito.Mockito.mockStatic
|
||||
import static org.mockito.Mockito.verify
|
||||
import static org.mockito.Mockito.when
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
class GspTemplateRendererTests {
|
||||
class GspTemplateRendererTests implements StandardDslConsumerTests {
|
||||
|
||||
private final TemplateRenderer renderer = new GspTemplateRenderer()
|
||||
|
||||
@Test
|
||||
void rendersPartWithNoBinding(@Mock PartRenderer partRenderer) {
|
||||
def template = new Template(
|
||||
"<%= parts['test'].render() %>",
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
when(partRenderer.render(any(), any(), any(), any(), any(), any(), any(), any()))
|
||||
.thenReturn(new Tuple2<>([], 'Hello, World!'))
|
||||
def partType = new PartType([], partRenderer)
|
||||
def part = new Part('test', partType, null)
|
||||
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[part],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
private Tuple2<Collection<Diagnostic>, String> doRender(String scriptlet, Text text, RenderContext context) {
|
||||
this.renderer.render(new Template(scriptlet, '', null), text, context)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersPartWithBinding(@Mock PartRenderer partRenderer) {
|
||||
def template = new Template(
|
||||
"<%= parts['greeting'].render([person: 'World']) %>",
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
when(partRenderer.render(
|
||||
any(),
|
||||
argThat { Map m -> m.get('person') == 'World' },
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any()
|
||||
)).thenReturn(new Tuple2<>([], 'Hello, World!'))
|
||||
|
||||
def partType = new PartType([], partRenderer)
|
||||
def part = new Part('greeting', partType, null)
|
||||
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[part],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersFrontMatter() {
|
||||
def template = new Template("<%= frontMatter['title'] %>", null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [title: ['Hello!']]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('Hello!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void rendersGlobal() {
|
||||
def template = new Template("<%= globals['test'] %>", null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[test: 'Hello, World!'],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
@Override
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context) {
|
||||
this.doRender(scriptlet, blankText(), context)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: refactor this and the super interface methods so that we can re-use rendering logic
|
||||
*/
|
||||
@Test
|
||||
void textAvailableToRender() {
|
||||
def template = new Template('<%= text.render() %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
renderableText('Hello, World!'),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
getRenderContext()
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('Hello, World!', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagBuilderAvailable() {
|
||||
def template = new Template('<%= tagBuilder.test() %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('<test />', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathAvailable() {
|
||||
def template = new Template('<%= path %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
textWithPath('test.md'),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('test.md', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlBuilderAvailable() {
|
||||
def template = new Template('<%= urlBuilder.relative("images/test.jpg") %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
'test.html'
|
||||
)
|
||||
assertTrue(r.v1.isEmpty(), getDiagnosticsMessageSupplier(r.v1))
|
||||
assertEquals('images/test.jpg', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlBuilderIsRelativeToTargetPath() {
|
||||
def template = new Template('<%= urlBuilder.relative("images/test.jpg") %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
'test/test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('../images/test.jpg', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void urlBuilderAbsolutePathCorrect() {
|
||||
def template = new Template('<%= urlBuilder.absolute %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', 'https://test.com'),
|
||||
[:],
|
||||
'test/test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('https://test.com/test/test.html', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void targetPathAvailable() {
|
||||
def template = new Template('<%= targetPath %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
'test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('test.html', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void siteSpecBaseUrlAvailable() {
|
||||
def template = new Template('<%= siteSpec.baseUrl %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', 'https://test.com'),
|
||||
[:],
|
||||
'test.html'
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
assertEquals('https://test.com', r.v2)
|
||||
}
|
||||
|
||||
@Test
|
||||
void loggerAvailable(@Mock Logger logger) {
|
||||
try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory)) {
|
||||
loggerFactory.when(() -> LoggerFactory.getLogger(anyString()))
|
||||
.thenReturn(logger)
|
||||
def template = new Template('<% logger.info "Hello, World!" %>', null, null)
|
||||
def r = this.renderer.render(
|
||||
template,
|
||||
new FrontMatter(null, [:]),
|
||||
blankText(),
|
||||
[],
|
||||
new SiteSpec('', ''),
|
||||
[:],
|
||||
''
|
||||
)
|
||||
assertEmptyDiagnostics(r)
|
||||
verify(logger).info('Hello, World!')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package com.jessebrault.ssg.dsl
|
||||
|
||||
interface DslScriptletProvider {
|
||||
String getGlobalsAvailable()
|
||||
String getRenderGlobal()
|
||||
|
||||
String getLoggerAvailable()
|
||||
|
||||
String getPartsAvailable()
|
||||
String getRenderPartFromParts()
|
||||
|
||||
String getSiteSpecAvailable()
|
||||
String getRenderSiteSpecValues()
|
||||
|
||||
String getSourcePathAvailable()
|
||||
String getRenderSourcePathValue()
|
||||
|
||||
String getTagBuilderAvailable()
|
||||
|
||||
String getTargetPathAvailable()
|
||||
String getRenderTargetPath()
|
||||
|
||||
String getTextsAvailable()
|
||||
String getRenderTextFromTexts()
|
||||
|
||||
String getUrlBuilderAvailable()
|
||||
String getUrlBuilderCorrectlyConfigured()
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package com.jessebrault.ssg.dsl
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.part.EmbeddablePartsMap
|
||||
import com.jessebrault.ssg.part.Part
|
||||
import com.jessebrault.ssg.part.PartRenderer
|
||||
import com.jessebrault.ssg.part.PartType
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
import com.jessebrault.ssg.tagbuilder.TagBuilder
|
||||
import com.jessebrault.ssg.text.EmbeddableTextsCollection
|
||||
import com.jessebrault.ssg.url.UrlBuilder
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockedStatic
|
||||
import org.mockito.junit.jupiter.MockitoExtension
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
import static com.jessebrault.ssg.testutil.DiagnosticsUtil.assertEmptyDiagnostics
|
||||
import static com.jessebrault.ssg.testutil.RenderContextUtil.getRenderContext
|
||||
import static com.jessebrault.ssg.text.TextMocks.renderableTextWithPath
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||
import static org.junit.jupiter.api.Assertions.fail
|
||||
import static org.mockito.ArgumentMatchers.any
|
||||
import static org.mockito.ArgumentMatchers.anyString
|
||||
import static org.mockito.Mockito.*
|
||||
|
||||
@ExtendWith(MockitoExtension)
|
||||
interface StandardDslConsumerTests {
|
||||
|
||||
Tuple2<Collection<Diagnostic>, String> render(String scriptlet, RenderContext context)
|
||||
|
||||
default void checkResult(String expected, Tuple2<Collection<Diagnostic>, String> result) {
|
||||
assertEmptyDiagnostics(result)
|
||||
assertEquals(expected, result.v2)
|
||||
}
|
||||
|
||||
default void doDslRenderTest(String expected, String scriptlet, RenderContext context = null) {
|
||||
this.checkResult(expected, this.render(scriptlet, context ?: getRenderContext()))
|
||||
}
|
||||
|
||||
default void doDslAssertionTest(String scriptlet, RenderContext context = null) {
|
||||
try {
|
||||
this.render(scriptlet, context ?: getRenderContext())
|
||||
} catch (AssertionError e) {
|
||||
fail(e)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
default void rendersGlobal() {
|
||||
this.doDslRenderTest(
|
||||
'Hello, World!',
|
||||
'<%= globals.test %>',
|
||||
getRenderContext(globals: [test: 'Hello, World!'])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void loggerAvailable(@Mock Logger logger) {
|
||||
try (MockedStatic<LoggerFactory> loggerFactory = mockStatic(LoggerFactory)) {
|
||||
loggerFactory.when { LoggerFactory.getLogger(anyString()) }
|
||||
.thenReturn(logger)
|
||||
|
||||
this.doDslAssertionTest('<% assert logger; logger.info("Hello, World!") %>')
|
||||
verify(logger).info('Hello, World!')
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
default void partsAvailable() {
|
||||
this.doDslAssertionTest("<% assert parts != null && parts instanceof ${ EmbeddablePartsMap.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void partAvailableAndRenderable(@Mock PartRenderer partRenderer) {
|
||||
when(partRenderer.render(any(), any(), any(), any()))
|
||||
.thenReturn(new Tuple2<>([], 'Hello, World!'))
|
||||
def part = new Part(
|
||||
'test.gsp',
|
||||
new PartType([], partRenderer),
|
||||
'Hello, World!'
|
||||
)
|
||||
this.doDslRenderTest(
|
||||
'Hello, World!',
|
||||
'<%= parts["test.gsp"].render() %>',
|
||||
getRenderContext(parts: [part])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void siteSpecAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
"<% assert siteSpec && siteSpec instanceof ${ SiteSpec.name } %>"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void siteSpecRendersCorrectValues() {
|
||||
def siteSpec = new SiteSpec('Test Site', 'https://test.com')
|
||||
this.doDslRenderTest(
|
||||
'Test Site https://test.com',
|
||||
'<%= siteSpec.name + " " + siteSpec.baseUrl %>',
|
||||
getRenderContext(siteSpec: siteSpec)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void sourcePathAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
'<% assert sourcePath && sourcePath instanceof String %>',
|
||||
getRenderContext(sourcePath: 'test.md')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void sourcePathRendersCorrectValue() {
|
||||
this.doDslRenderTest(
|
||||
'test.md',
|
||||
'<%= sourcePath %>',
|
||||
getRenderContext(sourcePath: 'test.md')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void tagBuilderAvailable() {
|
||||
this.doDslAssertionTest("<% assert tagBuider && tagBuilder instanceof ${ TagBuilder.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void targetPathAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
'<% assert targetPath && targetPath instanceof String %>',
|
||||
getRenderContext(targetPath: 'test/test.html')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void targetPathRendersCorrectValue() {
|
||||
this.doDslRenderTest(
|
||||
'test/test.html',
|
||||
'<%= targetPath %>',
|
||||
getRenderContext(targetPath: 'test/test.html')
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void textsAvailable() {
|
||||
this.doDslAssertionTest(
|
||||
"<% assert texts != null && texts instanceof ${ EmbeddableTextsCollection.name } %>"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void textsTextAvailableAndRenderable() {
|
||||
def testText = renderableTextWithPath('Hello, World!', 'test.md')
|
||||
this.doDslRenderTest(
|
||||
'Hello, World!',
|
||||
'<%= texts.find { it.path == "test.md" }.render() %>',
|
||||
getRenderContext(texts: [testText])
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
default void urlBuilderAvailable() {
|
||||
this.doDslAssertionTest("<% assert urlBuilder && urlBuilder instanceof ${ UrlBuilder.name } %>")
|
||||
}
|
||||
|
||||
@Test
|
||||
default void urlBuilderCorrectlyConfigured() {
|
||||
this.doDslRenderTest(
|
||||
'../images/test.jpg',
|
||||
'<%= urlBuilder.relative("images/test.jpg") %>',
|
||||
getRenderContext(targetPath: 'test/test.html')
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,8 @@ package com.jessebrault.ssg.testutil
|
||||
|
||||
import com.jessebrault.ssg.Diagnostic
|
||||
import com.jessebrault.ssg.text.ExcerptGetter
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.FirstParam
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue
|
||||
@ -23,10 +25,18 @@ class DiagnosticsUtil {
|
||||
assertTrue(result.v1.isEmpty(), getDiagnosticsMessageSupplier(result.v1))
|
||||
}
|
||||
|
||||
static void assertDiagnosticException(Class<? extends Exception> expectedException, Diagnostic diagnostic) {
|
||||
static <E extends Exception> void assertDiagnosticException(
|
||||
Class<E> expectedException,
|
||||
Diagnostic diagnostic,
|
||||
@ClosureParams(FirstParam.FirstGenericType)
|
||||
Closure<Void> additionalAssertions = null
|
||||
) {
|
||||
assertInstanceOf(expectedException, diagnostic.exception, {
|
||||
"Incorrect diagnostic exception class; message: ${ diagnostic.message }"
|
||||
})
|
||||
if (additionalAssertions) {
|
||||
additionalAssertions(diagnostic.exception)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.jessebrault.ssg.testutil
|
||||
|
||||
import com.jessebrault.ssg.Config
|
||||
import com.jessebrault.ssg.SiteSpec
|
||||
import com.jessebrault.ssg.renderer.RenderContext
|
||||
|
||||
class RenderContextUtil {
|
||||
|
||||
static RenderContext getRenderContext(Map args = null) {
|
||||
new RenderContext(
|
||||
args?.config as Config ?: new Config(),
|
||||
args?.siteSpec as SiteSpec ?: new SiteSpec('', ''),
|
||||
args?.globals as Map ?: [:],
|
||||
args?.texts as Collection ?: [],
|
||||
args?.parts as Collection ?: [],
|
||||
args?.sourcePath as String ?: '',
|
||||
args?.targetPath as String ?: ''
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -28,4 +28,12 @@ class TextMocks {
|
||||
new Text('', path, new TextType([], textRenderer, frontMatterGetter, excerptGetter))
|
||||
}
|
||||
|
||||
static Text renderableTextWithPath(String text, String path) {
|
||||
def textRenderer = mock(TextRenderer)
|
||||
when(textRenderer.render(any(), any())).thenReturn(new Tuple2<>([], text))
|
||||
def frontMatterGetter = mock(FrontMatterGetter)
|
||||
def excerptGetter = mock(ExcerptGetter)
|
||||
new Text('', path, new TextType([], textRenderer, frontMatterGetter, excerptGetter))
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user