add CLI test
This commit is contained in:
parent
4b2041f759
commit
37c46b7435
4 changed files with 126 additions and 24 deletions
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"oss.terrastruct.com/d2/d2cli"
|
"oss.terrastruct.com/d2/d2cli"
|
||||||
|
"oss.terrastruct.com/d2/lib/pptx"
|
||||||
"oss.terrastruct.com/util-go/assert"
|
"oss.terrastruct.com/util-go/assert"
|
||||||
"oss.terrastruct.com/util-go/diff"
|
"oss.terrastruct.com/util-go/diff"
|
||||||
"oss.terrastruct.com/util-go/xmain"
|
"oss.terrastruct.com/util-go/xmain"
|
||||||
|
|
@ -234,6 +235,32 @@ layers: {
|
||||||
testdataIgnoreDiff(t, ".pdf", pdf)
|
testdataIgnoreDiff(t, ".pdf", pdf)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "how_to_solve_problems_pptx",
|
||||||
|
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||||
|
writeFile(t, dir, "in.d2", `how to solve a hard problem?
|
||||||
|
steps: {
|
||||||
|
1: {
|
||||||
|
w: write down the problem
|
||||||
|
}
|
||||||
|
2: {
|
||||||
|
w -> t
|
||||||
|
t: think really hard about it
|
||||||
|
}
|
||||||
|
3: {
|
||||||
|
t -> w2
|
||||||
|
w2: write down the solution
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
err := runTestMain(t, ctx, dir, env, "in.d2", "how_to_solve_problems.pptx")
|
||||||
|
assert.Success(t, err)
|
||||||
|
|
||||||
|
file := readFile(t, dir, "how_to_solve_problems.pptx")
|
||||||
|
err = pptx.Validate(file, 4)
|
||||||
|
assert.Success(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "stdin",
|
name: "stdin",
|
||||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -19,21 +18,12 @@ func copyPptxTemplateTo(w *zip.Writer) error {
|
||||||
reader := bytes.NewReader(pptx_template)
|
reader := bytes.NewReader(pptx_template)
|
||||||
zipReader, err := zip.NewReader(reader, reader.Size())
|
zipReader, err := zip.NewReader(reader, reader.Size())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("%v", err)
|
fmt.Printf("error creating zip reader: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range zipReader.File {
|
for _, f := range zipReader.File {
|
||||||
fw, err := w.Create(f.Name)
|
if err := w.Copy(f); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("error copying %s: %v", f.Name, err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
fr, err := f.Open()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = io.Copy(fw, fr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -116,6 +106,7 @@ func getPresentationXml(slideFileNames []string) string {
|
||||||
|
|
||||||
builder.WriteString("<p:sldIdLst>")
|
builder.WriteString("<p:sldIdLst>")
|
||||||
for i, name := range slideFileNames {
|
for i, name := range slideFileNames {
|
||||||
|
// in the exported presentation, the first slide ID was 256, so keeping it here for compatibility
|
||||||
builder.WriteString(fmt.Sprintf(`<p:sldId id="%d" r:id="%s" />`, 256+i, name))
|
builder.WriteString(fmt.Sprintf(`<p:sldId id="%d" r:id="%s" />`, 256+i, name))
|
||||||
}
|
}
|
||||||
builder.WriteString("</p:sldIdLst>")
|
builder.WriteString("</p:sldIdLst>")
|
||||||
|
|
|
||||||
|
|
@ -88,10 +88,12 @@ func (p *Presentation) SaveTo(filePath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
zipFile := zip.NewWriter(f)
|
zipWriter := zip.NewWriter(f)
|
||||||
defer zipFile.Close()
|
defer zipWriter.Close()
|
||||||
|
|
||||||
copyPptxTemplateTo(zipFile)
|
if err = copyPptxTemplateTo(zipWriter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var slideFileNames []string
|
var slideFileNames []string
|
||||||
for i, slide := range p.Slides {
|
for i, slide := range p.Slides {
|
||||||
|
|
@ -99,7 +101,7 @@ func (p *Presentation) SaveTo(filePath string) error {
|
||||||
slideFileName := fmt.Sprintf("slide%d", i+1)
|
slideFileName := fmt.Sprintf("slide%d", i+1)
|
||||||
slideFileNames = append(slideFileNames, slideFileName)
|
slideFileNames = append(slideFileNames, slideFileName)
|
||||||
|
|
||||||
imageWriter, err := zipFile.Create(fmt.Sprintf("ppt/media/%s.png", imageId))
|
imageWriter, err := zipWriter.Create(fmt.Sprintf("ppt/media/%s.png", imageId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -108,13 +110,13 @@ func (p *Presentation) SaveTo(filePath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(zipFile, fmt.Sprintf("ppt/slides/_rels/%s.xml.rels", slideFileName), getRelsSlideXml(imageId))
|
err = addFile(zipWriter, fmt.Sprintf("ppt/slides/_rels/%s.xml.rels", slideFileName), getRelsSlideXml(imageId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(
|
err = addFile(
|
||||||
zipFile,
|
zipWriter,
|
||||||
fmt.Sprintf("ppt/slides/%s.xml", slideFileName),
|
fmt.Sprintf("ppt/slides/%s.xml", slideFileName),
|
||||||
getSlideXml(slide.BoardPath, imageId, slide.ImageTop, slide.ImageLeft, slide.ImageWidth, slide.ImageHeight),
|
getSlideXml(slide.BoardPath, imageId, slide.ImageTop, slide.ImageLeft, slide.ImageWidth, slide.ImageHeight),
|
||||||
)
|
)
|
||||||
|
|
@ -123,27 +125,27 @@ func (p *Presentation) SaveTo(filePath string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(zipFile, "[Content_Types].xml", getContentTypesXml(slideFileNames))
|
err = addFile(zipWriter, "[Content_Types].xml", getContentTypesXml(slideFileNames))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(zipFile, "ppt/_rels/presentation.xml.rels", getPresentationXmlRels(slideFileNames))
|
err = addFile(zipWriter, "ppt/_rels/presentation.xml.rels", getPresentationXmlRels(slideFileNames))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(zipFile, "ppt/presentation.xml", getPresentationXml(slideFileNames))
|
err = addFile(zipWriter, "ppt/presentation.xml", getPresentationXml(slideFileNames))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(zipFile, "docProps/core.xml", getCoreXml(p.Title, p.Subject, p.Description, p.Creator))
|
err = addFile(zipWriter, "docProps/core.xml", getCoreXml(p.Title, p.Subject, p.Description, p.Creator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = addFile(zipFile, "docProps/app.xml", getAppXml(p.Slides, p.D2Version))
|
err = addFile(zipWriter, "docProps/app.xml", getAppXml(p.Slides, p.D2Version))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
82
lib/pptx/validate.go
Normal file
82
lib/pptx/validate.go
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package pptx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Validate(pptxContent []byte, nSlides int) error {
|
||||||
|
reader := bytes.NewReader(pptxContent)
|
||||||
|
zipReader, err := zip.NewReader(reader, reader.Size())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error reading pptx content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedCount := getExpectedPptxFileCount(nSlides)
|
||||||
|
if len(zipReader.File) != expectedCount {
|
||||||
|
return fmt.Errorf("expected %d files, got %d", expectedCount, len(zipReader.File))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < nSlides; i++ {
|
||||||
|
if err := checkFile(zipReader, fmt.Sprintf("ppt/slides/slide%d.xml", i+1)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkFile(zipReader, fmt.Sprintf("ppt/slides/_rels/slide%d.xml.rels", i+1)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkFile(zipReader, fmt.Sprintf("ppt/media/slide%dImage.png", i+1)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range zipReader.File {
|
||||||
|
if !strings.Contains(file.Name, ".xml") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// checks if the XML content is valid
|
||||||
|
f, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error opening %s: %v", file.Name, err)
|
||||||
|
}
|
||||||
|
decoder := xml.NewDecoder(f)
|
||||||
|
for {
|
||||||
|
if err := decoder.Decode(new(interface{})); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return fmt.Errorf("error parsing xml content in %s: %v", file.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFile(reader *zip.Reader, fname string) error {
|
||||||
|
f, err := reader.Open(fname)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error opening file %s: %v", fname, err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if _, err = f.Stat(); err != nil {
|
||||||
|
return fmt.Errorf("error getting file info %s: %v", fname, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExpectedPptxFileCount(nSlides int) int {
|
||||||
|
reader := bytes.NewReader(pptx_template)
|
||||||
|
zipReader, err := zip.NewReader(reader, reader.Size())
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
baseFiles := len(zipReader.File)
|
||||||
|
presentationFiles := 5 // presentation, rels, app, core, content types
|
||||||
|
slideFiles := 3 * nSlides // slides, rels, images
|
||||||
|
return baseFiles + presentationFiles + slideFiles
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue