Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ import QtQuick
++ import QtTest
++ import QtLocation
++ import QtPositioning
++
++ Item {
++ Plugin { id: testPlugin1; name: "qmlgeo.test.plugin"; allowExperimental: true}
++ Plugin { id: errorPlugin; name: "qmlgeo.test.plugin"; allowExperimental: true
++ parameters: [
++ PluginParameter { name: "error"; value: "1"},
++ PluginParameter { name: "errorString"; value: "This error was expected. No worries !"}
++ ]
++ }
++
++
++ property variant coordinate1: QtPositioning.coordinate(51, 41)
++ property variant coordinate2: QtPositioning.coordinate(52, 42)
++ property variant coordinate3: QtPositioning.coordinate(53, 43)
++ property variant emptyCoordinate: QtPositioning.coordinate()
++
++ property variant boundingBox1: QtPositioning.rectangle(coordinate1, coordinate2)
++ property variant boundingBox2: QtPositioning.rectangle(coordinate1, coordinate3)
++ property variant boundingCircle1: QtPositioning.circle(coordinate1, 100)
++ property variant boundingCircle2: QtPositioning.circle(coordinate2, 100)
++
++ property variant emptyBox: QtPositioning.rectangle()
++
++ GeocodeModel {id: emptyModel}
++
++ Address {id: emptyAddress}
++ SignalSpy {id: querySpy; target: emptyModel; signalName: "queryChanged"}
++ SignalSpy {id: autoUpdateSpy; target: emptyModel; signalName: "autoUpdateChanged"}
++ SignalSpy {id: pluginSpy; target: emptyModel ; signalName: "pluginChanged"}
++ SignalSpy {id: boundsSpy; target: emptyModel; signalName: "boundsChanged"}
++ SignalSpy {id: limitSpy; target: emptyModel; signalName: "limitChanged"}
++ SignalSpy {id: offsetSpy; target: emptyModel; signalName: "offsetChanged"}
++
++ TestCase {
++ id: testCase1
++ name: "GeocodeModel"
++ function test_model_defaults_and_setters() {
++ // Query: address
++ compare (querySpy.count, 0)
++ emptyModel.query = address1
++ compare (querySpy.count, 1)
++ compare (emptyModel.query.street, address1.street)
++ emptyModel.query = address1
++ compare (querySpy.count, 1)
++ compare (emptyModel.query.street, address1.street)
++ // Query: coordinate
++ emptyModel.query = coordinate1
++ compare (querySpy.count, 2)
++ compare (emptyModel.query.latitude, coordinate1.latitude)
++ emptyModel.query = coordinate1
++ compare (querySpy.count, 2)
++ compare (emptyModel.query.latitude, coordinate1.latitude)
++ // Query: string
++ emptyModel.query = "Kuortane, Finland"
++ compare (querySpy.count, 3)
++ compare (emptyModel.query, "Kuortane, Finland")
++ emptyModel.query = "Kuortane, Finland"
++ compare (querySpy.count, 3)
++ compare (emptyModel.query, "Kuortane, Finland")
++
++ // limit and offset
++ compare (limitSpy.count, 0)
++ compare (offsetSpy.count, 0)
++ compare(emptyModel.limit, -1)
++ compare(emptyModel.offset, 0)
++ emptyModel.limit = 2
++ compare (limitSpy.count, 1)
++ emptyModel.limit = 2
++ compare (limitSpy.count, 1)
++ emptyModel.offset = 10
++ compare (offsetSpy.count, 1)
++ emptyModel.offset = 10
++ compare (offsetSpy.count, 1)
++
++ // bounding box
++ compare(boundsSpy.count, 0)
++ emptyModel.bounds = boundingBox1
++ compare(boundsSpy.count, 1)
++ compare(emptyModel.bounds.topLeft.latitude, boundingBox1.topLeft.latitude)
++ compare(emptyModel.bounds.bottomRight.longitude, boundingBox1.bottomRight.longitude)
++ emptyModel.bounds = boundingBox1
++ compare(boundsSpy.count, 1)
++ compare(emptyModel.bounds.topLeft.latitude, boundingBox1.topLeft.latitude)
++ compare(emptyModel.bounds.bottomRight.longitude, boundingBox1.bottomRight.longitude)
++ emptyModel.bounds = boundingBox2
++ compare(boundsSpy.count, 2)
++ compare(emptyModel.bounds.topLeft.latitude, boundingBox2.topLeft.latitude)
++ compare(emptyModel.bounds.bottomRight.longitude, boundingBox2.bottomRight.longitude)
++ emptyModel.bounds = QtPositioning.rectangle();
++ compare(boundsSpy.count, 3)
++
++
++ // bounding circle
++ boundsSpy.clear()
++ emptyModel.bounds = boundingCircle1
++ compare(boundsSpy.count, 1)
++ compare(emptyModel.bounds.center.latitude, coordinate1.latitude)
++ emptyModel.bounds = boundingCircle1
++ compare(boundsSpy.count, 1)
++ compare(emptyModel.bounds.center.latitude, coordinate1.latitude)
++ emptyModel.bounds = boundingCircle2
++ compare(boundsSpy.count, 2)
++ compare(emptyModel.bounds.center.latitude, coordinate2.latitude)
++ var dynamicCircle = QtPositioning.circle(QtPositioning.coordinate(8, 9));
++ emptyModel.bounds = dynamicCircle
++ compare(boundsSpy.count, 3)
++ compare(emptyModel.bounds.center.latitude, dynamicCircle.center.latitude)
++
++ // status
++ compare (emptyModel.status, GeocodeModel.Null)
++
++ // error
++ compare (emptyModel.errorString, "")
++ compare (emptyModel.error, GeocodeModel.NoError)
++
++ // count
++ compare( emptyModel.count, 0)
++
++ // auto update
++ compare (autoUpdateSpy.count, 0)
++ compare (emptyModel.autoUpdate, false)
++ emptyModel.autoUpdate = true
++ compare (emptyModel.autoUpdate, true)
++ compare (autoUpdateSpy.count, 1)
++ emptyModel.autoUpdate = true
++ compare (emptyModel.autoUpdate, true)
++ compare (autoUpdateSpy.count, 1)
++
++ // mustn't crash even we don't have plugin
++ emptyModel.update()
++
++ // Plugin
++ compare(pluginSpy.count, 0)
++ emptyModel.plugin = testPlugin1
++ compare(pluginSpy.count, 1)
++ compare(emptyModel.plugin, testPlugin1)
++ emptyModel.plugin = testPlugin1
++ compare(pluginSpy.count, 1)
++ emptyModel.plugin = errorPlugin
++ compare(pluginSpy.count, 2)
++ }
++ // Test that model acts gracefully when plugin is not set or is invalid
++ // (does not support geocoding)
++ GeocodeModel {id: errorModel; plugin: errorPlugin}
++ GeocodeModel {id: errorModelNoPlugin}
++ SignalSpy {id: countInvalidSpy; target: errorModel; signalName: "countChanged"}
++ SignalSpy {id: errorSpy; target: errorModel; signalName: "errorChanged"}
++ function test_error_plugin() {
++ // test plugin not set
++ compare(errorModelNoPlugin.error,GeocodeModel.NoError)
++ errorModelNoPlugin.update()
++ compare(errorModelNoPlugin.error,GeocodeModel.EngineNotSetError)
++ console.log(errorModelNoPlugin.errorString)
++
++ //plugin set but otherwise not offering anything
++ compare(errorModel.error,GeocodeModel.EngineNotSetError)
++ compare(errorModel.errorString,"This error was expected. No worries !")
++ errorSpy.clear()
++ errorModel.update()
++ compare(errorModel.error,GeocodeModel.EngineNotSetError)
++ compare(errorModel.errorString,qsTr("Cannot geocode, geocode manager not set."))
++ compare(errorSpy.count, 1)
++ errorSpy.clear()
++ errorModel.cancel()
++ compare(errorModel.error,GeocodeModel.NoError)
++ compare(errorModel.errorString,"")
++ compare(errorSpy.count, 1)
++ errorSpy.clear()
++ errorModel.reset()
++ compare(errorModel.error,GeocodeModel.NoError)
++ compare(errorModel.errorString,"")
++ compare(errorSpy.count, 0)
++ errorSpy.clear()
++ errorModel.update()
++ compare(errorModel.error,GeocodeModel.EngineNotSetError)
++ compare(errorModel.errorString,qsTr("Cannot geocode, geocode manager not set."))
++ compare(errorSpy.count, 1)
++ errorSpy.clear()
++ var location = errorModel.get(-1)
++ compare(location, null)
++ }
++
++ }
++ Address {id: address1; street: "wellknown street"; city: "expected city"; county: "2"}
++ Address {id: errorAddress1; street: "error"; county: "2"} // street is the error reason
++
++ property variant rcoordinate1: QtPositioning.coordinate(51, 2)
++ property variant errorCoordinate1: QtPositioning.coordinate(73, 2) // (latiude mod 70) is the error code
++ property variant slackCoordinate1: QtPositioning.coordinate(60, 3)
++ Address {id: slackAddress1; street: "Slacker st"; city: "Lazy town"; county: "4"}
++
++ property variant automaticCoordinate1: QtPositioning.coordinate(60, 3)
++ Address {id: automaticAddress1; street: "Auto st"; city: "Detroit"; county: "4"}
++
++ Plugin {
++ id: testPlugin2;
++ name: "qmlgeo.test.plugin"
++ allowExperimental: true
++ parameters: [
++ // Parms to guide the test plugin
++ PluginParameter { name: "supported"; value: true},
++ PluginParameter { name: "finishRequestImmediately"; value: true},
++ PluginParameter { name: "validateWellKnownValues"; value: true}
++ ]
++ }
++
++ Plugin {
++ id: immediatePlugin;
++ name: "qmlgeo.test.plugin"
++ allowExperimental: true
++ parameters: [
++ // Parms to guide the test plugin
++ PluginParameter { name: "supported"; value: true},
++ PluginParameter { name: "finishRequestImmediately"; value: true},
++ PluginParameter { name: "validateWellKnownValues"; value: false}
++ ]
++ }
++
++ Plugin {
++ id: slackPlugin;
++ allowExperimental: true
++ name: "qmlgeo.test.plugin"
++ parameters: [
++ // Parms to guide the test plugin
++ PluginParameter { name: "supported"; value: true},
++ PluginParameter { name: "finishRequestImmediately"; value: false},
++ PluginParameter { name: "validateWellKnownValues"; value: false}
++ ]
++ }
++
++ Plugin {
++ id: autoPlugin;
++ allowExperimental: true
++ name: "qmlgeo.test.plugin"
++ parameters: [
++ // Parms to guide the test plugin
++ PluginParameter { name: "supported"; value: true},
++ PluginParameter { name: "finishRequestImmediately"; value: false},
++ PluginParameter { name: "validateWellKnownValues"; value: false}
++ ]
++ }
++
++ Plugin {
++ id: extendedPlugin;
++ name: "qmlgeo.test.plugin";
++ allowExperimental: true
++ PluginParameter { name: "finishRequestImmediately"; value: false}
++ PluginParameter { name: "includeExtendedData"; value: true }
++ }
++
++ GeocodeModel {id: testModel; plugin: testPlugin2}
++ SignalSpy {id: locationsSpy; target: testModel; signalName: "locationsChanged"}
++ SignalSpy {id: countSpy; target: testModel; signalName: "countChanged"}
++ SignalSpy {id: testQuerySpy; target: testModel; signalName: "queryChanged"}
++ SignalSpy {id: testStatusSpy; target: testModel; signalName: "statusChanged"}
++
++ GeocodeModel {id: slackModel; plugin: slackPlugin; }
++ SignalSpy {id: locationsSlackSpy; target: slackModel; signalName: "locationsChanged"}
++ SignalSpy {id: countSlackSpy; target: slackModel; signalName: "countChanged"}
++ SignalSpy {id: querySlackSpy; target: slackModel; signalName: "queryChanged"}
++ SignalSpy {id: errorStringSlackSpy; target: slackModel; signalName: "errorChanged"}
++ SignalSpy {id: errorSlackSpy; target: slackModel; signalName: "errorChanged"}
++ SignalSpy {id: pluginSlackSpy; target: slackModel; signalName: "pluginChanged"}
++
++ GeocodeModel {id: immediateModel; plugin: immediatePlugin}
++ SignalSpy {id: locationsImmediateSpy; target: immediateModel; signalName: "locationsChanged"}
++ SignalSpy {id: countImmediateSpy; target: immediateModel; signalName: "countChanged"}
++ SignalSpy {id: queryImmediateSpy; target: immediateModel; signalName: "queryChanged"}
++ SignalSpy {id: statusImmediateSpy; target: immediateModel; signalName: "statusChanged"}
++ SignalSpy {id: errorStringImmediateSpy; target: immediateModel; signalName: "errorChanged"}
++ SignalSpy {id: errorImmediateSpy; target: immediateModel; signalName: "errorChanged"}
++
++ GeocodeModel {id: automaticModel; plugin: autoPlugin; query: automaticAddress1; autoUpdate: true}
++ SignalSpy {id: automaticLocationsSpy; target: automaticModel; signalName: "locationsChanged"}
++
++ GeocodeModel {id: extendedModel; plugin: extendedPlugin; query: automaticAddress1; autoUpdate: true}
++ SignalSpy {id: extendedLocationsSpy; target: extendedModel; signalName: "locationsChanged"}
++
++ TestCase {
++ name: "GeocodeModelGeocoding"
++ function clear_slack_model() {
++ slackModel.reset()
++ locationsSlackSpy.clear()
++ countSlackSpy.clear()
++ querySlackSpy.clear()
++ errorStringSlackSpy.clear()
++ errorSlackSpy.clear()
++ slackModel.limit = -1
++ slackModel.offset = 0
++ }
++ function clear_immediate_model() {
++ immediateModel.reset()
++ locationsImmediateSpy.clear()
++ countImmediateSpy.clear()
++ queryImmediateSpy.clear()
++ errorStringImmediateSpy.clear()
++ errorImmediateSpy.clear()
++ statusImmediateSpy.clear()
++ immediateModel.limit = -1
++ immediateModel.offset = 0
++ }
++ function test_reset() {
++ clear_immediate_model();
++ immediateModel.query = errorAddress1
++ immediateModel.update()
++ compare (immediateModel.errorString, errorAddress1.street)
++ compare (immediateModel.error, GeocodeModel.CommunicationError)
++ compare (immediateModel.count, 0)
++ compare (statusImmediateSpy.count, 2)
++ compare (immediateModel.status, GeocodeModel.Error)
++ immediateModel.reset()
++ compare (immediateModel.errorString, "")
++ compare (immediateModel.error, GeocodeModel.NoError)
++ compare (immediateModel.status, GeocodeModel.Null)
++ // Check that ongoing req is aborted
++ clear_slack_model()
++ slackModel.query = slackAddress1
++ slackAddress1.county = "5"
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 0)
++ compare (locationsSlackSpy.count, 0)
++ compare (slackModel.count, 0)
++ slackModel.reset()
++ tryCompare(countSlackSpy, "count", 0)
++ compare (locationsSlackSpy.count, 0)
++ compare (slackModel.count, 0)
++ // Check that results are cleared
++ slackModel.update()
++ tryCompare(slackModel, "count", 5)
++ slackModel.reset()
++ compare (slackModel.count, 0)
++ // Check that changing plugin resets any ongoing requests
++ clear_slack_model()
++ slackModel.query = slackAddress1
++ slackAddress1.county = "7"
++ compare (pluginSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 0)
++ slackModel.plugin = errorPlugin
++ tryCompare(countSlackSpy, "count", 0)
++ compare (pluginSlackSpy.count, 1)
++ // switch back and check that works
++ slackModel.plugin = slackPlugin
++ compare (pluginSlackSpy.count, 2)
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 0)
++ tryCompare(countSlackSpy, "count", 1)
++ }
++ function test_error_geocode() {
++ // basic immediate geocode error
++ clear_immediate_model()
++ immediateModel.query = errorAddress1
++ immediateModel.update()
++ compare (errorStringImmediateSpy.count, 1)
++ compare (immediateModel.errorString, errorAddress1.street)
++ compare (immediateModel.error, GeocodeModel.CommunicationError) // county of the address (2)
++ compare (immediateModel.count, 0)
++ compare (statusImmediateSpy.count, 2)
++ compare (immediateModel.status, GeocodeModel.Error)
++ // basic delayed geocode error
++ clear_slack_model()
++ slackModel.query = errorAddress1
++ errorAddress1.street = "error code 2"
++ slackModel.update()
++ compare (errorStringSlackSpy.count, 0)
++ compare (errorSlackSpy.count, 0)
++ tryCompare (errorStringSlackSpy, "count", 1)
++ tryCompare (errorSlackSpy, "count", 1)
++ compare (slackModel.errorString, errorAddress1.street)
++ compare (slackModel.error, GeocodeModel.CommunicationError)
++ compare (slackModel.count, 0)
++ // Check that we recover
++ slackModel.query = address1
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 1)
++ compare (slackModel.count, 2)
++ compare (errorStringSlackSpy.count, 2)
++ compare (errorSlackSpy.count, 2)
++ compare (slackModel.errorString, "")
++ compare (slackModel.error, GeocodeModel.NoError)
++ }
++
++ function test_error_reverse_geocode() {
++ // basic immediate geocode error
++ clear_immediate_model()
++ immediateModel.query = errorCoordinate1
++ immediateModel.update()
++ if (immediateModel.errorString != "")
++ compare (errorStringImmediateSpy.count, 1) // the previous error is cleared upon update()
++ else
++ compare (errorImmediateSpy.count, 1)
++ compare (immediateModel.errorString, "error")
++ compare (immediateModel.error, GeocodeModel.ParseError)
++ compare (immediateModel.count, 0)
++ compare (statusImmediateSpy.count, 2)
++ compare (immediateModel.status, GeocodeModel.Error)
++ // basic delayed geocode error
++ clear_slack_model()
++ slackModel.query = errorCoordinate1
++ slackModel.update()
++ compare (errorStringSlackSpy.count, 0)
++ compare (errorSlackSpy.count, 0)
++ if (slackModel.errorString != "")
++ tryCompare (errorStringSlackSpy, "count", 2)
++ else
++ tryCompare (errorStringSlackSpy, "count", 1)
++ compare (slackModel.errorString, "error")
++ compare (slackModel.error, GeocodeModel.ParseError)
++ compare (slackModel.count, 0)
++ // Check that we recover
++ slackModel.query = rcoordinate1
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 1)
++ compare (slackModel.count, 2)
++ compare (errorStringSlackSpy.count, 2)
++ compare (errorSlackSpy.count, 2)
++ compare (slackModel.errorString, "")
++ compare (slackModel.error, GeocodeModel.NoError)
++ }
++ function test_address_geocode() {
++ testQuerySpy.clear()
++ locationsSpy.clear()
++ testStatusSpy.clear()
++ testModel.reset()
++ countSpy.clear()
++ compare (locationsSpy.count, 0)
++ compare (testModel.errorString, "")
++ compare (testModel.error, GeocodeModel.NoError)
++ compare (testModel.count, 0)
++ testModel.query = address1
++ compare (testQuerySpy.count, 1)
++ testModel.update()
++ tryCompare (locationsSpy, "count", 1) // 5 sec
++ compare (testModel.errorString, "")
++ compare (testModel.error, GeocodeModel.NoError)
++ compare (testModel.count, 2)
++ compare (testQuerySpy.count, 1)
++ compare (testStatusSpy.count, 2)
++ compare (testModel.status, GeocodeModel.Ready)
++ compare (testModel.get(0).address.street, "wellknown street")
++ compare (testModel.get(0).address.city, "expected city")
++ }
++
++ function test_freetext_geocode() {
++ testQuerySpy.clear()
++ locationsSpy.clear()
++ testStatusSpy.clear()
++ testModel.reset()
++ countSpy.clear()
++ compare (locationsSpy.count, 0)
++ compare (testModel.errorString, "")
++ compare (testModel.error, GeocodeModel.NoError)
++ compare (testModel.count, 0)
++ testModel.limit = 5 // number of places echoed back
++ testModel.offset = 10 // 'county' set in the places
++ // Test successful case
++ testModel.query = "Freetext geocode"
++ compare(testQuerySpy.count, 1)
++ testModel.update();
++ tryCompare (locationsSpy, "count", 1) // 5 sec
++ tryCompare(countSpy, "count", 1)
++ tryCompare(testModel, "count", 5)
++ compare(testModel.get(0).address.county, "10")
++ // Test error case
++ testModel.query = "2" // tells plugin to echo error '2'
++ compare(testQuerySpy.count, 2)
++ testModel.update();
++ tryCompare (locationsSpy, "count", 2) // 5 sec
++ tryCompare(countSpy, "count", 2)
++ tryCompare(testModel, "count", 0)
++ compare(testModel.errorString, "2")
++ compare (testModel.error, GeocodeModel.CommunicationError)
++ testModel.reset()
++ tryCompare(countSpy, "count", 2)
++ compare (testModel.count, 0)
++ }
++
++ function test_delayed_freetext_geocode() {
++ clear_slack_model()
++ slackModel.limit = 5 // number of places echoed back
++ slackModel.offset = 10 // 'county' set in the places
++ // Basic successful case
++ slackModel.query = "freetext geocode"
++ compare (querySlackSpy.count, 1)
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 0)
++ compare (locationsSlackSpy.count, 0)
++ compare (slackModel.count, 0)
++ tryCompare(countSlackSpy, "count", 1); //waits up to 5s
++ compare (slackModel.count, 5)
++ compare (locationsSlackSpy.count, 1)
++ // Frequent updates, previous requests are aborted
++ slackModel.reset()
++ locationsSlackSpy.clear()
++ countSlackSpy.clear()
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ tryCompare(countSlackSpy, "count", 1); //waits up to 5s
++ compare (locationsSlackSpy.count, 1)
++ compare(slackModel.count, 5) // limit
++ }
++
++ function test_geocode_auto_updates() {
++ compare (automaticModel.count, 4) // should be something already
++ compare (automaticLocationsSpy.count, 1)
++ // change query and its contents and verify that autoupdate occurs
++ automaticAddress1.county = 6
++ tryCompare(automaticLocationsSpy, "count", 2)
++ compare (automaticModel.count, 6)
++ automaticAddress1.street = "The Avenue"
++ tryCompare(automaticLocationsSpy, "count", 3)
++ compare (automaticModel.count, 6)
++ automaticModel.query = automaticCoordinate1
++ tryCompare(automaticLocationsSpy, "count", 4)
++ compare (automaticModel.count, 3)
++ }
++
++ function test_geocode_extended_attributes() {
++ compare (extendedModel.count, 6) // should be something already
++ compare (extendedLocationsSpy.count, 3)
++ compare(extendedModel.get(0).extendedAttributes
++ ["QGeoCodingManagerEngineTest_locationExtendedAttribute"], 42)
++ // change query and its contents and verify that autoupdate occurs
++ extendedModel.query = automaticCoordinate1
++ tryCompare(extendedLocationsSpy, "count", 4)
++ compare (extendedModel.count, 3)
++ compare(extendedModel.get(0).extendedAttributes
++ ["QGeoCodingManagerEngineTest_locationExtendedAttribute"], 42)
++ }
++
++ function test_delayed_geocode() {
++ // basic delayed response
++ slackModel.reset()
++ querySlackSpy.clear()
++ countSlackSpy.clear()
++ locationsSlackSpy.clear()
++ slackModel.query = slackAddress1
++ slackAddress1.county = "7"
++ compare (querySlackSpy.count, 1)
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 0)
++ compare (locationsSlackSpy.count, 0)
++ compare (slackModel.count, 0)
++ tryCompare(countSlackSpy, "count", 1); //waits up to 5s
++ compare (locationsSlackSpy.count, 1)
++ compare (slackModel.count, 7) // slackAddress1.county)
++ // Frequent updates, previous requests are aborted
++ slackModel.reset()
++ locationsSlackSpy.clear()
++ countSlackSpy.clear()
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ tryCompare(countSlackSpy, "count", 1); //waits up to 5s
++ compare (locationsSlackSpy.count, 1)
++ compare(slackModel.count, 7) // slackAddress1.county
++ }
++ function test_reverse_geocode() {
++ testModel.reset()
++ testQuerySpy.clear()
++ locationsSpy.clear()
++ testStatusSpy.clear()
++ countSpy.clear()
++ compare (testModel.errorString, "")
++ compare (testModel.error, GeocodeModel.NoError)
++ compare (testModel.count, 0)
++ compare (testQuerySpy.count, 0)
++ testModel.query = rcoordinate1
++ compare (testQuerySpy.count, 1)
++ testModel.update()
++ tryCompare (locationsSpy, "count", 1) // 5 sec
++ tryCompare(countSpy, "count", 1)
++ compare (testModel.errorString, "")
++ compare (testModel.error, GeocodeModel.NoError)
++ compare (testModel.count, 2)
++ testModel.reset()
++ tryCompare(countSpy, "count", 2)
++ compare (testModel.count, 0)
++ }
++ function test_delayed_reverse_geocode() {
++ clear_slack_model()
++ slackModel.query = slackCoordinate1
++ compare (querySlackSpy.count, 1)
++ slackModel.update()
++ tryCompare(countSlackSpy, "count", 0)
++ compare (locationsSlackSpy.count, 0)
++ compare (slackModel.count, 0)
++
++ tryCompare(countSlackSpy, "count", 1); //waits up to 5s
++ compare (locationsSlackSpy.count, 1)
++ compare (slackModel.count, 3) // slackCoordinate1.longitude
++ // Frequent updates, previous requests are aborted
++ slackModel.reset()
++ locationsSlackSpy.clear()
++ countSlackSpy.clear()
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++ slackModel.update()
++ tryCompare(locationsSlackSpy, "count", 0)
++ compare(countSlackSpy.count, 0)
++
++ tryCompare(countSlackSpy, "count", 1); //waits up to 5s
++ compare(locationsSlackSpy.count, 1)
++ compare(slackModel.count, 3) // slackCoordinate1.longitude
++ }
++ }
++ }