Files
grecia/spec/models/geozone_spec.rb
CoslaJohn 5dbe2cbf24 Support FeatureCollection and MultiPolygon in geozones
We're reworking the format validation to correctly interpret feature
collection, feature, and geometry, according to RFC 7946 [1].

Since Leaflet interprets GeoJSON format, we're rendering the GeoJSON as
a layer instead of as a set of points. For that, we're normalizing the
GeoJSON to make sure it contains either a Feature or a
FeatureCollection. We're also adding the Leaflet images to the assets
path so the markers used for point geometries are rendered correctly.

Note we no longer allow a GeoJSON containing a geometry but not a
defined type. Since there might be invalid GeoJSON in existing Consul
Democracy databases, we're normalizing these existing geometry objects
to be part of a feature object.

We're also wrapping the outline points in a FeatureCollection object
because most of the large GIS systems eg ArcGIS, QGIS export geojson as
a complete FeatureCollection.

[1] https://datatracker.ietf.org/doc/html/rfc7946

Co-authored-by: Javi Martín <javim@elretirao.net>
2024-12-23 17:35:33 +01:00

213 lines
5.6 KiB
Ruby

require "rails_helper"
describe Geozone do
let(:geozone) { build(:geozone) }
it "is valid" do
expect(geozone).to be_valid
end
it "is not valid without a name" do
geozone.name = nil
expect(geozone).not_to be_valid
end
it "is valid without geojson" do
geozone.geojson = nil
expect(geozone).to be_valid
end
it "is not valid with invalid geojson file format" do
geozone.geojson = <<~JSON
{
"type": "Feature",
"geometry": {
"type": "Incorrect",
"coordinates": [
[40.8792937308316, -3.9259027239257],
[40.8788966596619, -3.9249047078766],
[40.8789131852224, -3.9247799675785]
]
}
}
JSON
expect(geozone).not_to be_valid
end
describe "#safe_to_destroy?" do
let(:geozone) { create(:geozone) }
it "is true when not linked to other models" do
expect(geozone).to be_safe_to_destroy
end
it "is false when already linked to user" do
create(:user, geozone: geozone)
expect(geozone).not_to be_safe_to_destroy
end
it "is false when already linked to proposal" do
create(:proposal, geozone: geozone)
expect(geozone).not_to be_safe_to_destroy
end
it "is false when already linked to debate" do
create(:debate, geozone: geozone)
expect(geozone).not_to be_safe_to_destroy
end
it "is false when already linked to a heading" do
create(:budget_heading, geozone: geozone)
expect(geozone).not_to be_safe_to_destroy
end
end
describe "#outline_points" do
it "returns nil when geojson is nil" do
geozone.geojson = nil
expect(geozone.outline_points).to be nil
end
it "returns normalized feature collection when geojson is a valid FeatureCollection" do
geozone.geojson = <<~JSON
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}]
}
JSON
expected = {
type: "FeatureCollection",
features: [{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}]
}
expect(geozone.outline_points).to eq expected.to_json
end
it "returns normalized feature collection when geojson is a valid Feature" do
geozone.geojson = <<~JSON
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}
JSON
expected = {
type: "FeatureCollection",
features: [{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}]
}
expect(geozone.outline_points).to eq expected.to_json
end
it "returns normalized feature collection when geojson is a valid Geometry object" do
geozone.geojson = <<~JSON
{
"geometry": {
"type": "Polygon",
"coordinates": [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}
JSON
expected = {
type: "FeatureCollection",
features: [{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}]
}
expect(geozone.outline_points).to eq expected.to_json
end
it "returns normalized feature collection when geojson is a valid top-level Geometry object" do
geozone.geojson = <<~JSON
{
"type": "Polygon",
"coordinates": [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
JSON
expected = {
type: "FeatureCollection",
features: [{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [[
[-3.9259027239257, 40.8792937308316],
[-3.9249047078766, 40.8788966596619],
[-3.9247799675785, 40.8789131852224],
[-3.9259027239257, 40.8792937308316]
]]
}
}]
}
expect(geozone.outline_points).to eq expected.to_json
end
end
end