summaryrefslogtreecommitdiff
path: root/xgb_test.go
diff options
context:
space:
mode:
authorAndrew Gallant (Ocelot) <[email protected]>2012-05-10 17:01:42 -0400
committerAndrew Gallant (Ocelot) <[email protected]>2012-05-10 17:01:42 -0400
commitb618b2ea09167306cfe29b6966faf184bc893c2d (patch)
treeebd8b505ebd83db1b891bc7a7f70d75f26e581e6 /xgb_test.go
parentb10760ea62c5c071496a71d1d9ab6752989a309f (diff)
a huge commit. splitting extensions into their own sub-packages.
Diffstat (limited to 'xgb_test.go')
-rw-r--r--xgb_test.go376
1 files changed, 0 insertions, 376 deletions
diff --git a/xgb_test.go b/xgb_test.go
deleted file mode 100644
index d0e840a..0000000
--- a/xgb_test.go
+++ /dev/null
@@ -1,376 +0,0 @@
-package xgb
-
-/*
- Tests for XGB.
-
- These tests only test the core X protocol at the moment. It isn't even
- close to complete coverage (and probably never will be), but it does test
- a number of different corners: requests with no replies, requests without
- replies, checked (i.e., synchronous) errors, unchecked (i.e., asynchronous)
- errors, and sequence number wrapping.
-
- There are also a couple of benchmarks that show the difference between
- correctly issuing lots of requests and gathering replies and
- incorrectly doing the same. (This particular difference is one of the
- claimed advantages of the XCB, and therefore XGB, family.
-*/
-
-import (
- "fmt"
- "log"
- "math/rand"
- "testing"
- "time"
-)
-
-// The X connection used throughout testing.
-var X *Conn
-
-// init initializes the X connection, seeds the RNG and starts waiting
-// for events.
-func init() {
- var err error
-
- X, err = NewConn()
- if err != nil {
- log.Fatal(err)
- }
-
- rand.Seed(time.Now().UnixNano())
-
- go grabEvents()
-}
-
-/******************************************************************************/
-// Tests
-/******************************************************************************/
-
-// TestSynchronousError purposefully causes a BadWindow error in a
-// MapWindow request, and checks it synchronously.
-func TestSynchronousError(t *testing.T) {
- err := X.MapWindowChecked(0).Check() // resource id 0 is always invalid
- if err == nil {
- t.Fatalf("MapWindow: A MapWindow request that should return an " +
- "error has returned a nil error.")
- }
- verifyMapWindowError(t, err)
-}
-
-// TestAsynchronousError does the same thing as TestSynchronousError, but
-// grabs the error asynchronously instead.
-func TestAsynchronousError(t *testing.T) {
- X.MapWindow(0) // resource id 0 is always invalid
-
- evOrErr := waitForEvent(t, 5)
- if evOrErr.ev != nil {
- t.Fatalf("After issuing an erroneous MapWindow request, we have "+
- "received an event rather than an error: %s", evOrErr.ev)
- }
- verifyMapWindowError(t, evOrErr.err)
-}
-
-// TestCookieBuffer issues (2^16) + n requets *without* replies to guarantee
-// that the sequence number wraps and that the cookie buffer will have to
-// flush itself (since there are no replies coming in to flush it).
-// And just like TestSequenceWrap, we issue another request with a reply
-// at the end to make sure XGB is still working properly.
-func TestCookieBuffer(t *testing.T) {
- n := (1 << 16) + 10
- for i := 0; i < n; i++ {
- X.NoOperation()
- }
- TestProperty(t)
-}
-
-// TestSequenceWrap issues (2^16) + n requests w/ replies to guarantee that the
-// sequence number (which is a 16 bit integer) will wrap. It then issues one
-// final request to ensure things still work properly.
-func TestSequenceWrap(t *testing.T) {
- n := (1 << 16) + 10
- for i := 0; i < n; i++ {
- _, err := X.InternAtom(false, 5, "RANDO").Reply()
- if err != nil {
- t.Fatalf("InternAtom: %s", err)
- }
- }
- TestProperty(t)
-}
-
-// TestProperty tests whether a random value can be set and read.
-func TestProperty(t *testing.T) {
- propName := randString(20) // whatevs
- writeVal := randString(20)
- readVal, err := changeAndGetProp(propName, writeVal)
- if err != nil {
- t.Error(err)
- }
-
- if readVal != writeVal {
- t.Errorf("The value written, '%s', is not the same as the "+
- "value read '%s'.", writeVal, readVal)
- }
-}
-
-// TestWindowEvents creates a window, maps it, listens for configure notify
-// events, issues a configure request, and checks for the appropriate
-// configure notify event.
-// This probably violates the notion of "test one thing and test it well,"
-// but testing X stuff is unique since it involves so much state.
-// Each request is checked to make sure there are no errors returned. If there
-// is an error, the test is failed.
-// You may see a window appear quickly and then disappear. Do not be alarmed :P
-// It's possible that this test will yield a false negative because we cannot
-// control our environment. That is, the window manager could override the
-// placement set. However, we set override redirect on the window, so the
-// window manager *shouldn't* touch our window if it is well-behaved.
-func TestWindowEvents(t *testing.T) {
- // The geometry to set the window.
- gx, gy, gw, gh := 200, 400, 1000, 300
-
- wid, err := X.NewWindowId()
- if err != nil {
- t.Fatalf("NewId: %s", err)
- }
-
- screen := X.DefaultScreen() // alias
- err = X.CreateWindowChecked(screen.RootDepth, wid, screen.Root,
- 0, 0, 500, 500, 0,
- WindowClassInputOutput, screen.RootVisual,
- CwBackPixel|CwOverrideRedirect, []uint32{0xffffffff, 1}).Check()
- if err != nil {
- t.Fatalf("CreateWindow: %s", err)
- }
-
- err = X.MapWindowChecked(wid).Check()
- if err != nil {
- t.Fatalf("MapWindow: %s", err)
- }
-
- // We don't listen in the CreateWindow request so that we don't get
- // a MapNotify event.
- err = X.ChangeWindowAttributesChecked(wid,
- CwEventMask, []uint32{EventMaskStructureNotify}).Check()
- if err != nil {
- t.Fatalf("ChangeWindowAttributes: %s", err)
- }
-
- err = X.ConfigureWindowChecked(wid,
- ConfigWindowX|ConfigWindowY|
- ConfigWindowWidth|ConfigWindowHeight,
- []uint32{uint32(gx), uint32(gy), uint32(gw), uint32(gh)}).Check()
- if err != nil {
- t.Fatalf("ConfigureWindow: %s", err)
- }
-
- err = X.ConfigureWindowChecked(wid,
- ConfigWindowX|ConfigWindowY|
- ConfigWindowWidth|ConfigWindowHeight,
- []uint32{uint32(gx + 2), uint32(gy), uint32(gw), uint32(gh)}).Check()
- if err != nil {
- t.Fatalf("ConfigureWindow: %s", err)
- }
-
- err = X.ConfigureWindowChecked(wid,
- ConfigWindowX|ConfigWindowY|
- ConfigWindowWidth|ConfigWindowHeight,
- []uint32{uint32(gx + 1), uint32(gy), uint32(gw), uint32(gh)}).Check()
- if err != nil {
- t.Fatalf("ConfigureWindow: %s", err)
- }
-
- TestProperty(t)
-
- evOrErr := waitForEvent(t, 5)
- switch event := evOrErr.ev.(type) {
- case ConfigureNotifyEvent:
- if event.X != int16(gx) {
- t.Fatalf("x was set to %d but ConfigureNotify reports %d",
- gx, event.X)
- }
- if event.Y != int16(gy) {
- t.Fatalf("y was set to %d but ConfigureNotify reports %d",
- gy, event.Y)
- }
- if event.Width != uint16(gw) {
- t.Fatalf("width was set to %d but ConfigureNotify reports %d",
- gw, event.Width)
- }
- if event.Height != uint16(gh) {
- t.Fatalf("height was set to %d but ConfigureNotify reports %d",
- gh, event.Height)
- }
- default:
- t.Fatalf("Expected a ConfigureNotifyEvent but got %T instead.", event)
- }
-
- // Okay, clean up!
- err = X.ChangeWindowAttributesChecked(wid,
- CwEventMask, []uint32{0}).Check()
- if err != nil {
- t.Fatalf("ChangeWindowAttributes: %s", err)
- }
-
- err = X.DestroyWindowChecked(wid).Check()
- if err != nil {
- t.Fatalf("DestroyWindow: %s", err)
- }
-}
-
-/******************************************************************************/
-// Benchmarks
-/******************************************************************************/
-
-// BenchmarkInternAtomsGood shows how many requests with replies
-// *should* be sent and gathered from the server. Namely, send as many
-// requests as you can at once, then go back and gather up all the replies.
-// More importantly, this approach can exploit parallelism when
-// GOMAXPROCS > 1.
-// Run with `go test -run 'nomatch' -bench '.*' -cpu 1,2,6` if you have
-// multiple cores to see the improvement that parallelism brings.
-func BenchmarkInternAtomsGood(b *testing.B) {
- b.StopTimer()
- names := seqNames(b.N)
-
- b.StartTimer()
- cookies := make([]InternAtomCookie, b.N)
- for i := 0; i < b.N; i++ {
- cookies[i] = X.InternAtom(false, uint16(len(names[i])), names[i])
- }
- for _, cookie := range cookies {
- cookie.Reply()
- }
-}
-
-// BenchmarkInternAtomsBad shows how *not* to issue a lot of requests with
-// replies. Namely, each subsequent request isn't issued *until* the last
-// reply is made. This implies a round trip to the X server for every
-// iteration.
-func BenchmarkInternAtomsPoor(b *testing.B) {
- b.StopTimer()
- names := seqNames(b.N)
-
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- X.InternAtom(false, uint16(len(names[i])), names[i]).Reply()
- }
-}
-
-/******************************************************************************/
-// Helper functions
-/******************************************************************************/
-
-// changeAndGetProp sets property 'prop' with value 'val'.
-// It then gets the value of that property and returns it.
-// (It's used to check that the 'val' going in is the same 'val' going out.)
-// It tests both requests with and without replies (GetProperty and
-// ChangeProperty respectively.)
-func changeAndGetProp(prop, val string) (string, error) {
- propAtom, err := X.InternAtom(false, uint16(len(prop)), prop).Reply()
- if err != nil {
- return "", fmt.Errorf("InternAtom: %s", err)
- }
-
- typName := "UTF8_STRING"
- typAtom, err := X.InternAtom(false, uint16(len(typName)), typName).Reply()
- if err != nil {
- return "", fmt.Errorf("InternAtom: %s", err)
- }
-
- err = X.ChangePropertyChecked(PropModeReplace, X.DefaultScreen().Root,
- propAtom.Atom, typAtom.Atom, 8, uint32(len(val)), []byte(val)).Check()
- if err != nil {
- return "", fmt.Errorf("ChangeProperty: %s", err)
- }
-
- reply, err := X.GetProperty(false, X.DefaultScreen().Root, propAtom.Atom,
- GetPropertyTypeAny, 0, (1<<32)-1).Reply()
- if err != nil {
- return "", fmt.Errorf("GetProperty: %s", err)
- }
- if reply.Format != 8 {
- return "", fmt.Errorf("Property reply format is %d but it should be 8.",
- reply.Format)
- }
-
- return string(reply.Value), nil
-}
-
-// verifyMapWindowError takes an error that is returned with an invalid
-// MapWindow request with a window Id of 0 and makes sure the error is the
-// right type and contains the correct values.
-func verifyMapWindowError(t *testing.T, err error) {
- switch e := err.(type) {
- case WindowError:
- if e.BadValue != 0 {
- t.Fatalf("WindowError should report a bad value of 0 but "+
- "it reports %d instead.", e.BadValue)
- }
- if e.MajorOpcode != 8 {
- t.Fatalf("WindowError should report a major opcode of 8 "+
- "(which is a MapWindow request), but it reports %d instead.",
- e.MajorOpcode)
- }
- default:
- t.Fatalf("Expected a WindowError but got %T instead.", e)
- }
-}
-
-// randString generates a random string of length n.
-func randString(n int) string {
- byts := make([]byte, n)
- for i := 0; i < n; i++ {
- rando := rand.Intn(53)
- switch {
- case rando <= 25:
- byts[i] = byte(65 + rando)
- case rando <= 51:
- byts[i] = byte(97 + rando - 26)
- default:
- byts[i] = ' '
- }
- }
- return string(byts)
-}
-
-// seqNames creates a slice of NAME0, NAME1, ..., NAMEN.
-func seqNames(n int) []string {
- names := make([]string, n)
- for i := range names {
- names[i] = fmt.Sprintf("NAME%d", i)
- }
- return names
-}
-
-// evErr represents a value that is either an event or an error.
-type evErr struct {
- ev Event
- err Error
-}
-
-// channel used to pass evErrs.
-var evOrErrChan = make(chan evErr, 0)
-
-// grabEvents is a goroutine that reads events off the wire.
-// We used this instead of WaitForEvent directly in our tests so that
-// we can timeout and fail a test.
-func grabEvents() {
- for {
- ev, err := X.WaitForEvent()
- evOrErrChan <- evErr{ev, err}
- }
-}
-
-// waitForEvent asks the evOrErrChan channel for an event.
-// If it doesn't get an event in 'n' seconds, the current test is failed.
-func waitForEvent(t *testing.T, n int) evErr {
- var evOrErr evErr
-
- select {
- case evOrErr = <-evOrErrChan:
- case <-time.After(time.Second * 5):
- t.Fatalf("After waiting 5 seconds for an event or an error, " +
- "we have timed out.")
- }
-
- return evOrErr
-}