func (s *S) TearDownTest(c *C) { s.engine.Destroy() retries := 30 // Three seconds top. for { // Do not call qml.Flush here. It creates a nested event loop // that attempts to process the deferred object deletes and cannot, // because deferred deletes are only processed at the same loop level. // So it *reposts* the deferred deletion event, in practice *preventing* // these objects from being deleted. runtime.GC() stats := qml.Stats() if stats.EnginesAlive == 0 && stats.ValuesAlive == 0 && stats.ConnectionsAlive == 0 { break } if retries == 0 { panic(fmt.Sprintf("there are values alive:\n%#v\n", stats)) } retries-- time.Sleep(100 * time.Millisecond) if retries%10 == 0 { c.Logf("There are still objects alive; waiting for them to die: %#v\n", stats) } } qml.SetLogger(nil) }
func (s *S) SetUpTest(c *C) { qml.SetLogger(c) qml.CollectStats(true) qml.ResetStats() stats := qml.Stats() if stats.EnginesAlive > 0 || stats.ValuesAlive > 0 || stats.ConnectionsAlive > 0 { panic(fmt.Sprintf("Test started with values alive: %#v\n", stats)) } s.engine = qml.NewEngine() s.context = s.engine.Context() }
`, Done: func(c *TestData) { c.Check(c.root.Call("f").(qml.Object).Int("width"), Equals, 300) }, }, { Summary: "Call a QML method that holds a custom type past the return point", QML: ` Item { property var held function hold(v) { held = v; gc(); gc(); } function log() { console.log("String is", held.stringValue) } }`, Done: func(c *TestData) { value := GoType{StringValue: "<content>"} stats := qml.Stats() c.root.Call("hold", &value) c.Check(qml.Stats().ValuesAlive, Equals, stats.ValuesAlive+1) c.root.Call("log") c.root.Call("hold", nil) c.Check(qml.Stats().ValuesAlive, Equals, stats.ValuesAlive) }, DoneLog: "String is <content>", }, { Summary: "Call a non-existent QML method", QML: `Item {}`, Done: func(c *TestData) { c.Check(func() { c.root.Call("add", 1, 2) }, Panics, `object does not expose a method "add"`) }, },