package main import ( "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 createTable = `CREATE TABLE result_raw ( expected INT NOT NULL, actual INT NOT NULL );` var createView string = `CREATE VIEW result AS SELECT ` + sqlViewColSpec() + ` FROM result_raw;` func NewSQLite(path string) (*SQLiteEmitter, error) { conn, err := sqlite.OpenConn(path, sqlite.OpenCreate|sqlite.OpenReadWrite|sqlite.OpenWAL) if err != nil { return nil, err } fmt.Println(createView) err = sqlitex.Execute(conn, createTable, &sqlitex.ExecOptions{}) if err != nil { return nil, fmt.Errorf("NewSQLite: cannot create table: %w", err) } err = sqlitex.Execute(conn, createView, &sqlitex.ExecOptions{}) if err != nil { return nil, fmt.Errorf("NewSQLite: cannot create view: %w", err) } return &SQLiteEmitter{ conn: conn, }, nil } func (s *SQLiteEmitter) Emit(r Result) error { return sqlitex.Execute(s.conn, "INSERT INTO result_raw(expected, actual) VALUES (?, ?)", &sqlitex.ExecOptions{ Args: []any{r.Expected, r.Actual}, }) } func emitCSV(r Result) error { _, err := fmt.Printf("%03o,%03o\n", r.Expected, r.Actual) if err != nil { return fmt.Errorf("emitCSV: %w", err) } return nil } func getData(emit func(Result) error) (err error) { f, err := os.CreateTemp("", "go-perm-test-*") if err != nil { return err } path := f.Name() f.Close() 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 { var emit func(Result) error if len(os.Args) < 2 { emit = emitCSV } else { dbPath := os.Args[1] db, err := NewSQLite(dbPath) if err != nil { return err } defer db.Close() emit = db.Emit } return getData(emit) } func main() { err := run() if err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err) os.Exit(1) } }