package main import ( "errors" "fmt" "io/fs" "os" "strings" "zombiezen.com/go/sqlite" "zombiezen.com/go/sqlite/sqlitex" ) type Result struct{ Expected, Actual fs.FileMode } type SQLiteEmitter struct { conn *sqlite.Conn } func (s *SQLiteEmitter) Close() error { return s.conn.Close() } func sqlViewColSpec() string { var cols []string var whos = []rune{'o', 'g', 'u'} var whats = []rune{'x', 'w', 'r'} for _, fieldName := range []string{"expected", "actual"} { cols = append(cols, fmt.Sprintf("%s", fieldName)) for iwho, who := range whos { cols = append(cols, fmt.Sprintf("%[1]s & (7 << %[3]d * 3) >> (%[3]d * 3) AS %[1]s_%[2]c", fieldName, who, iwho)) for iwhat, what := range whats { cols = append(cols, fmt.Sprintf("%[1]s & (1 << %[3]d * 3 + %[5]d) >> (%[3]d * 3 + %[5]d) AS %[1]s_%[2]c%[4]c", fieldName, who, iwho, what, iwhat)) } } } return strings.Join(cols, ",\n") } const createTableFile = `CREATE TABLE file_result_raw ( expected INT NOT NULL, actual INT NOT NULL );` var createViewFile string = `CREATE VIEW file_result AS SELECT ` + sqlViewColSpec() + ` FROM file_result_raw;` var createTableDir = strings.ReplaceAll(createTableFile, "file_result", "dir_result") var createViewDir = strings.ReplaceAll(createViewFile, "file_result", "dir_result") func NewSQLite(path string) (*SQLiteEmitter, error) { conn, err := sqlite.OpenConn(path, sqlite.OpenCreate|sqlite.OpenReadWrite|sqlite.OpenWAL) if err != nil { return nil, err } script := strings.Join([]string{createTableFile, createTableDir, createViewFile, createViewDir}, "\n") fmt.Println(script) err = sqlitex.ExecuteScript(conn, script, &sqlitex.ExecOptions{}) if err != nil { return nil, fmt.Errorf("NewSQLite: cannot create schema: %w", err) } // err = sqlitex.Execute(conn, createTableFile, &sqlitex.ExecOptions{}) // if err != nil { // return nil, fmt.Errorf("NewSQLite: cannot create table: %w", err) // } // err = sqlitex.Execute(conn, createViewFile, &sqlitex.ExecOptions{}) // if err != nil { // return nil, fmt.Errorf("NewSQLite: cannot create view: %w", err) // } return &SQLiteEmitter{ conn: conn, }, nil } func (s *SQLiteEmitter) Emit(tablePrefix string) func(r Result) error { query := fmt.Sprintf("INSERT INTO %sresult_raw(expected, actual) VALUES (?, ?)", tablePrefix) return func(r Result) error { return sqlitex.Execute(s.conn, query, &sqlitex.ExecOptions{ Args: []any{r.Expected, r.Actual}, }) } } func createFile(dir, pattern string) (path string, err error) { f, err := os.CreateTemp(dir, pattern) if err != nil { return "", err } f.Close() return f.Name(), nil } func getData(create func(string, string) (string, error), emit func(Result) error) (err error) { path, err := create("", "go-perm-test-*") if err != nil { return err } for mode := fs.FileMode(0); mode <= os.ModePerm; mode++ { err := os.Chmod(path, mode) if err != nil { return fmt.Errorf("cannot set mode 0%03o on %s: %w", mode, path, err) } info, err := os.Stat(path) if err != nil { return fmt.Errorf("cannot stat %s: %w", path, err) } result := Result{ Expected: mode, Actual: info.Mode(), } err = emit(result) if err != nil { return err } } return nil } func run() error { if len(os.Args) < 2 { fmt.Fprintf(os.Stderr, "usage: %s ", os.Args[0]) } dbPath := os.Args[1] db, err := NewSQLite(dbPath) if err != nil { return err } defer db.Close() return errors.Join(getData(createFile, db.Emit("file_")), getData(os.MkdirTemp, db.Emit("dir_"))) } func main() { err := run() if err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err) os.Exit(1) } }