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"
|
||||
|
||||
"oss.terrastruct.com/d2/d2cli"
|
||||
"oss.terrastruct.com/d2/lib/pptx"
|
||||
"oss.terrastruct.com/util-go/assert"
|
||||
"oss.terrastruct.com/util-go/diff"
|
||||
"oss.terrastruct.com/util-go/xmain"
|
||||
|
|
@ -234,6 +235,32 @@ layers: {
|
|||
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",
|
||||
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -19,21 +18,12 @@ func copyPptxTemplateTo(w *zip.Writer) error {
|
|||
reader := bytes.NewReader(pptx_template)
|
||||
zipReader, err := zip.NewReader(reader, reader.Size())
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
fmt.Printf("error creating zip reader: %v", err)
|
||||
}
|
||||
|
||||
for _, f := range zipReader.File {
|
||||
fw, err := w.Create(f.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fr, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(fw, fr)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := w.Copy(f); err != nil {
|
||||
return fmt.Errorf("error copying %s: %v", f.Name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -116,6 +106,7 @@ func getPresentationXml(slideFileNames []string) string {
|
|||
|
||||
builder.WriteString("<p:sldIdLst>")
|
||||
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("</p:sldIdLst>")
|
||||
|
|
|
|||
|
|
@ -88,10 +88,12 @@ func (p *Presentation) SaveTo(filePath string) error {
|
|||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
zipFile := zip.NewWriter(f)
|
||||
defer zipFile.Close()
|
||||
zipWriter := zip.NewWriter(f)
|
||||
defer zipWriter.Close()
|
||||
|
||||
copyPptxTemplateTo(zipFile)
|
||||
if err = copyPptxTemplateTo(zipWriter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var slideFileNames []string
|
||||
for i, slide := range p.Slides {
|
||||
|
|
@ -99,7 +101,7 @@ func (p *Presentation) SaveTo(filePath string) error {
|
|||
slideFileName := fmt.Sprintf("slide%d", i+1)
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
@ -108,13 +110,13 @@ func (p *Presentation) SaveTo(filePath string) error {
|
|||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addFile(
|
||||
zipFile,
|
||||
zipWriter,
|
||||
fmt.Sprintf("ppt/slides/%s.xml", slideFileName),
|
||||
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 {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addFile(zipFile, "ppt/presentation.xml", getPresentationXml(slideFileNames))
|
||||
err = addFile(zipWriter, "ppt/presentation.xml", getPresentationXml(slideFileNames))
|
||||
if err != nil {
|
||||
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 {
|
||||
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 {
|
||||
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