1 | var test = require('tape')
|
2 | var contentType = require('content-type')
|
3 | var parsexml = require('xml-parser')
|
4 | var hyperquest = require('hyperquest')
|
5 | var concat = require('concat-stream')
|
6 | var createServer = require('./lib/test_server.js')
|
7 |
|
8 | var base, server, changeId
|
9 |
|
10 | test('bbox.js: setup changeset server', function (t) {
|
11 | createServer(function (d) {
|
12 | base = d.base
|
13 | server = d.server
|
14 | t.end()
|
15 | })
|
16 | })
|
17 |
|
18 | test('create bbox', function (t) {
|
19 | t.plan(4)
|
20 | var href = base + 'changeset/create'
|
21 | var hq = hyperquest.put(href, {
|
22 | headers: { 'content-type': 'text/xml' }
|
23 | })
|
24 | hq.once('response', function (res) {
|
25 | t.equal(res.statusCode, 200, 'create 200 ok')
|
26 | var contentObj = contentType.parse(res)
|
27 | t.equal(contentObj.type, 'text/plain', 'media type correct')
|
28 | t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
|
29 | })
|
30 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
31 | changeId = body.trim()
|
32 | t.ok(/^[0-9A-Fa-f]+$/.test(changeId), 'expected changeset id response')
|
33 | }))
|
34 | hq.end('<osm><changeset></changeset></osm>')
|
35 | })
|
36 |
|
37 | var uploaded = {}
|
38 | var SIZE = 100
|
39 | test('add docs to changeset', function (t) {
|
40 | t.plan(4)
|
41 | var docs = []
|
42 | for (var i = 0; i < SIZE; i++) {
|
43 | docs.push({
|
44 | type: 'node',
|
45 | id: 0 - i - 1,
|
46 | lat: 64 + i / SIZE,
|
47 | lon: -121 - i / SIZE,
|
48 | changeset: changeId
|
49 | })
|
50 | }
|
51 | docs.push({
|
52 | type: 'way',
|
53 | id: 0 - i - 1,
|
54 | changeset: changeId,
|
55 | refs: docs.map(function (d, i) { return 0 - (i + 1) })
|
56 | })
|
57 | var kdocs = {}
|
58 | docs.forEach(function (doc, i) {
|
59 | kdocs[0 - i - 1] = doc
|
60 | })
|
61 |
|
62 | var href = base + 'changeset/' + changeId + '/upload'
|
63 | var hq = hyperquest.post(href, {
|
64 | headers: { 'content-type': 'text/xml' }
|
65 | })
|
66 | hq.once('response', function (res) {
|
67 | t.equal(res.statusCode, 200)
|
68 | var contentObj = contentType.parse(res)
|
69 | t.equal(contentObj.type, 'text/xml', 'media type correct')
|
70 | t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
|
71 | })
|
72 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
73 | var xml = parsexml(body)
|
74 | t.equal(xml.root.name, 'diffResult')
|
75 | xml.root.children.forEach(function (node, i) {
|
76 | var id = node.attributes.new_id
|
77 | uploaded[id] = kdocs[0 - i - 1]
|
78 | uploaded[id].id = id
|
79 | if (node.name === 'way') {
|
80 | uploaded[id].refs = uploaded[id].refs.map(function (ref) {
|
81 | return kdocs[ref].id
|
82 | })
|
83 | }
|
84 | })
|
85 | }))
|
86 | hq.end(`<osmChange version="1.0">
|
87 | <create>
|
88 | ${docs.map(function (doc) {
|
89 | return `<${doc.type} changeset="${doc.changeset}"
|
90 | id="${doc.id}"
|
91 | ${doc.lat ? `lat="${doc.lat}"` : ''}
|
92 | ${doc.lon ? `lon="${doc.lon}"` : ''}>
|
93 | ${(doc.refs || []).map(function (ref) {
|
94 | return `<nd ref="${ref}"/>`
|
95 | }).join('\n')}
|
96 | </${doc.type}>`
|
97 | }).join('\n')}
|
98 | </create>
|
99 | </osmChange>`)
|
100 | })
|
101 |
|
102 | test('bbox', function (t) {
|
103 | t.plan(8 + SIZE * 3)
|
104 | var href = base + 'map?bbox=-123,63,-120,66'
|
105 | var hq = hyperquest(href)
|
106 | hq.once('response', function (res) {
|
107 | t.equal(res.statusCode, 200)
|
108 | t.equal(res.headers['content-type'].split(/\s*;\s*/)[0], 'text/xml')
|
109 | })
|
110 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
111 | var xml = parsexml(body)
|
112 | t.equal(xml.root.name, 'osm')
|
113 | t.equal(xml.root.children[0].name, 'bounds')
|
114 | t.deepEqual(xml.root.children[0].attributes, { maxlat: '66', maxlon: '-120', minlat: '63', minlon: '-123' }, 'bounds matches request')
|
115 | t.ok(orderedTypes(xml.root.children.map(function (c) {
|
116 | return c.name
|
117 | })), 'ordered types')
|
118 |
|
119 | for (var i = 1; i < xml.root.children.length; i++) {
|
120 | var c = xml.root.children[i]
|
121 | var node = uploaded[c.attributes.id]
|
122 | if (c.name === 'node') {
|
123 | t.equal(c.attributes.changeset, node.changeset)
|
124 | t.equal(c.attributes.lat, String(node.lat))
|
125 | t.equal(c.attributes.lon, String(node.lon))
|
126 | } else if (c.name === 'way') {
|
127 | t.equal(c.children.length, SIZE, 'way')
|
128 | t.deepEqual(c.children.map(function (nd) {
|
129 | return nd.attributes.ref
|
130 | }), node.refs, 'way refs')
|
131 | }
|
132 | }
|
133 | }))
|
134 | })
|
135 |
|
136 | test('missing bbox', function (t) {
|
137 | t.plan(4)
|
138 | var href = base + 'map'
|
139 | var hq = hyperquest(href)
|
140 | hq.once('response', function (res) {
|
141 | t.equal(res.statusCode, 400)
|
142 | var contentObj = contentType.parse(res)
|
143 | t.equal(contentObj.type, 'text/plain', 'media type correct')
|
144 | t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
|
145 | })
|
146 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
147 | t.equal(body, 'Missing bbox query string parameter')
|
148 | }))
|
149 | })
|
150 |
|
151 | test('invalid bbox', function (t) {
|
152 | t.plan(4)
|
153 | var href = base + 'map?bbox=invalid'
|
154 | var hq = hyperquest(href)
|
155 | hq.once('response', function (res) {
|
156 | t.equal(res.statusCode, 400)
|
157 | var contentObj = contentType.parse(res)
|
158 | t.equal(contentObj.type, 'text/plain', 'media type correct')
|
159 | t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
|
160 | })
|
161 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
162 | t.equal(body, 'Invalid bbox query string parameter')
|
163 | }))
|
164 | })
|
165 |
|
166 | test('out of range bbox', function (t) {
|
167 | t.plan(4)
|
168 | var href = base + 'map?bbox=-181,1,2,2'
|
169 | var hq = hyperquest(href)
|
170 | hq.once('response', function (res) {
|
171 | t.equal(res.statusCode, 400)
|
172 | var contentObj = contentType.parse(res)
|
173 | t.equal(contentObj.type, 'text/plain', 'media type correct')
|
174 | t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
|
175 | })
|
176 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
177 | t.equal(body, 'Invalid bbox query string parameter')
|
178 | }))
|
179 | })
|
180 |
|
181 | test('bbox json', function (t) {
|
182 | t.plan(7 + SIZE * 3)
|
183 | var href = base + 'map?bbox=-123,63,-120,66'
|
184 | var hq = hyperquest(href, {headers: { 'Accept': 'application/json' }})
|
185 | hq.once('response', function (res) {
|
186 | t.equal(res.statusCode, 200)
|
187 | t.equal(res.headers['content-type'].split(/\s*;\s*/)[0], 'application/json')
|
188 | })
|
189 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
190 | var json = JSON.parse(body)
|
191 | t.equal(json.version, 0.6)
|
192 | t.deepEqual(json.bounds, { maxlat: 66, maxlon: -120, minlat: 63, minlon: -123 }, 'bounds matches request')
|
193 | t.ok(orderedTypes(json.elements.map(function (c) {
|
194 | return c.type
|
195 | })), 'ordered types')
|
196 |
|
197 | for (var i = 0; i < json.elements.length; i++) {
|
198 | var c = json.elements[i]
|
199 | var node = uploaded[c.id]
|
200 | if (c.type === 'node') {
|
201 | t.equal(c.changeset, node.changeset)
|
202 | t.equal(c.lat, node.lat)
|
203 | t.equal(c.lon, node.lon)
|
204 | } else if (c.type === 'way') {
|
205 | t.equal(c.nodes.length, SIZE, 'way')
|
206 | t.deepEqual(c.nodes, node.refs, 'way refs')
|
207 | }
|
208 | }
|
209 | }))
|
210 | })
|
211 |
|
212 | test('bbox json /w forks', function (t) {
|
213 | t.plan(7 + SIZE * 3)
|
214 | var href = base + 'map?bbox=-123,63,-120,66&forks=true'
|
215 | var hq = hyperquest(href, {headers: { 'Accept': 'application/json' }})
|
216 | hq.once('response', function (res) {
|
217 | t.equal(res.statusCode, 200)
|
218 | t.equal(res.headers['content-type'].split(/\s*;\s*/)[0], 'application/json')
|
219 | })
|
220 | hq.pipe(concat({ encoding: 'string' }, function (body) {
|
221 | var json = JSON.parse(body)
|
222 | t.equal(json.version, 0.6)
|
223 | t.deepEqual(json.bounds, { maxlat: 66, maxlon: -120, minlat: 63, minlon: -123 }, 'bounds matches request')
|
224 | t.ok(orderedTypes(json.elements.map(function (c) {
|
225 | return c.type
|
226 | })), 'ordered types')
|
227 |
|
228 | for (var i = 0; i < json.elements.length; i++) {
|
229 | var c = json.elements[i]
|
230 | var node = uploaded[c.id]
|
231 | if (c.type === 'node') {
|
232 | t.equal(c.changeset, node.changeset)
|
233 | t.equal(c.lat, node.lat)
|
234 | t.equal(c.lon, node.lon)
|
235 | } else if (c.type === 'way') {
|
236 | t.equal(c.nodes.length, SIZE, 'way')
|
237 | t.deepEqual(c.nodes, node.refs, 'way refs')
|
238 | }
|
239 | }
|
240 | }))
|
241 | })
|
242 |
|
243 | test('bbox.js: teardown server', function (t) {
|
244 | server.cleanup(function () {
|
245 | t.end()
|
246 | })
|
247 | })
|
248 |
|
249 | function orderedTypes (types) {
|
250 | var order = { bounds: 0, node: 0, way: 1, relation: 2 }
|
251 | for (var i = 1; i < types.length; i++) {
|
252 | if (order[types[i - 1]] > order[types[i]]) return false
|
253 | }
|
254 | return true
|
255 | }
|