Include types from gonavitia/navitia

This commit is contained in:
nemunaire 2023-07-14 12:23:33 +02:00
parent 82769f923e
commit 24b1102761
157 changed files with 26062 additions and 116 deletions

5
go.mod
View File

@ -4,6 +4,10 @@ go 1.18
require (
github.com/gin-gonic/gin v1.9.1
github.com/mb0/wkt v0.0.0-20170420051526-a30afd545ee1
github.com/paulmach/go.geojson v1.5.0
github.com/pkg/errors v0.9.1
github.com/twpayne/go-geom v1.5.2
golang.org/x/text v0.11.0
)
@ -30,6 +34,5 @@ require (
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

126
go.sum
View File

@ -1,12 +1,9 @@
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -14,38 +11,15 @@ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@ -54,144 +28,66 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/mb0/wkt v0.0.0-20170420051526-a30afd545ee1 h1:VCgV+ng800r1/AChRHzHbWCtQI06cPxoZQUljQHTyXc=
github.com/mb0/wkt v0.0.0-20170420051526-a30afd545ee1/go.mod h1:IhobDa5AIyiMAsnH/qkytD0NbG0JMOJ2ihQqe1NdXyg=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/paulmach/go.geojson v1.5.0 h1:7mhpMK89SQdHFcEGomT7/LuJhwhEgfmpWYVlVmLEdQw=
github.com/paulmach/go.geojson v1.5.0/go.mod h1:DgdUy2rRVDDVgKqrjMe2vZAHMfhDTrjVKt3LmHIXGbU=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/twpayne/go-geom v1.5.2 h1:LyRfBX2W0LM7XN/bGqX0XxrJ7SZc3XwmxU4aj4kSoxw=
github.com/twpayne/go-geom v1.5.2/go.mod h1:3z6O2sAnGtGCXx4Q+5nPOLCA5e8WI2t3cthdb1P2HH8=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

4
types/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.zip
Fuzz*Dir/
*.prof
*.test

78
types/README.md Normal file
View File

@ -0,0 +1,78 @@
# navitia/types is a library for working with types returned by the [Navitia](navitia.io) API. [![GoDoc](https://godoc.org/github.com/govitia/navitia/types?status.svg)](https://godoc.org/github.com/govitia/navitia/types)
Package types implements support for the types used in the Navitia API (see doc.navitia.io), simplified and modified for idiomatic Go use.
This is navitia/types v0.2. It is not API-Stable, and won't be until the v1 release of navitia, but it's getting closer !
This package was and is developped as a supporting library for the [navitia API client](https://github.com/govitia/navitia) but can be used to build other navitia API clients.
## Install
Simply run `go get -u github.com/govitia/navitia/types`.
## Coverage
Preview of the supported types, see [the doc](https://godoc.org/github.com/govitia/navitia-types) for more information, and the [navitia.io doc](http://doc.navitia.io) for information about the remote API.
|Type Name|Description|Navitia Name|
|---|---|---|
|[`Journey`](https://godoc.org/github.com/govitia/navitia-types#Journey)|A journey (X-->Y)|"journey"|
|[`Section`](https://godoc.org/github.com/govitia/navitia-types#Section)|A section of a `Journey`|"section"|
|[`Region`](https://godoc.org/github.com/govitia/navitia-types#Region)|A region covered by the API|"region"|
|[`Isochrone`](https://godoc.org/github.com/govitia/navitia-types#Region)|A region covered by the API|"isochrone"|
|[`Container`](https://godoc.org/github.com/govitia/navitia-types#Container)|This contains a Place or a PTObject|"place"/"pt_object"|
|[`Place`](https://godoc.org/github.com/govitia/navitia-types#Place)|Place is an empty interface, by convention used to identify an `Address`, [`StopPoint`](https://godoc.org/github.com/govitia/navitia-types#StopPoint), [`StopArea`](https://godoc.org/github.com/govitia/navitia-types#StopArea), [`POI`](https://godoc.org/github.com/govitia/navitia-types#POI), [`Admin`](https://godoc.org/github.com/govitia/navitia-types#Admin) & [`Coordinates`](https://godoc.org/github.com/govitia/navitia-types#Coordinates).|
|[`PTObject`](https://godoc.org/github.com/govitia/navitia-types#Place)|PTObject is an empty interface by convention used to identify a Public Transportation object|
|[`Line`](https://godoc.org/github.com/govitia/navitia-types#Line)|A public transit line.|"line"|
|[`Route`](https://godoc.org/github.com/govitia/navitia-types#Route)|A specific route within a `Line`.|"route"|
And others, such as [`Display`](https://godoc.org/github.com/govitia/navitia-types#Display) ["display_informations"], [`PTDateTime`](https://godoc.org/github.com/govitia/navitia-types#PTDateTime) ["pt-date-time"], [`StopTime`](https://godoc.org/github.com/govitia/navitia-types#StopTime) ["stop_time"]
## Getting started
```golang
import (
"fmt"
"github.com/govitia/navitia/types"
)
func main() {
data := []byte{"some journey's json"}
var j types.Journey
_ = j.UnmarshalJSON(data)
}
```
### Going further
Obviously, this is a very simple example of what navitia/types can do, [check out the documentation !](https://godoc.org/github.com/govitia/navitia/types)
## What's new in v0.2
- Merge back into the `navitia` tree !
- `Container` is now a type that can be used as a Place Container or as a PTObject Container, which helps everyone!
- No more `String` methods
- Better unmarshalling, including better error handling, along with better testing
- Benchmarks !
- `Disruption` support, along with what it entails.
- Rename `JourneyStatus` to `Effect`
- And others ! See `git log` for more information !
## TODO
### Documentation
- Update `readme.md` to reflect new changes
- Add links to the doc.navitia.io documentation to every type
### Testing
- `(*PTDateTime).UnmarshalJSON`
- `ErrInvalidPlaceContainer.Error`
- `Equipment.Known`
- Every Type should have at least one file to be tested against
- Globalise mutual code in unmarshal testers
## Footnotes
I made this project as I wanted to explore and push my go skills, and I'm really up for you to contribute ! Send me a pull request and/or contact me if you have any questions! ( [@aabizri](https://twitter.com/aabizri) on twitter)

6
types/activePeriod.go Normal file
View File

@ -0,0 +1,6 @@
package types
type ActivePeriod struct {
Begin string `json:"begin"`
End string `json:"end"`
}

9
types/calendar.go Normal file
View File

@ -0,0 +1,9 @@
package types
// Calendar is returned on vehicle journey message and indicates periodicity informations
// about transport schedules.
type Calendar struct {
ActivePeriods []ActivePeriod `json:"active_periods"`
WeekPattern WeekPattern `json:"week_pattern"`
Exceptions []Exception `json:"exceptions"`
}

9
types/channel.go Normal file
View File

@ -0,0 +1,9 @@
package types
// A Channel is a destination media for a message.
type Channel struct {
ID ID `json:"id"` // ID of the address
ContentType string `json:"content_type"` // Content Type (text/html etc.) RFC1341.4
Name string `json:"name"` // Name of the channel
Types []string `json:"types,omitempty"` // Types ?
}

65
types/common_test.go Normal file
View File

@ -0,0 +1,65 @@
package types
import (
"encoding/json"
"reflect"
"testing"
)
// testUnmarshal is a helper to test unmarshalling for any value implementing results.
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func testUnmarshal(t *testing.T, data typeTestData, resultsType reflect.Type) {
t.Helper()
// Create the run function generator, allowing us to run this in parallel
rgen := func(data []byte, correct bool) func(t *testing.T) {
return func(t *testing.T) {
// Declare this test to be run in parallel
t.Parallel()
// Create a pointer to a new value of the type indicated in resultsType
res := reflect.New(resultsType).Interface()
// We use encoding/json's unmarshaller, as we don't have one for this type
err := json.Unmarshal(data, res)
// We check that the result is what we expect:
// If we expect no errors (correct == true) but we get one, the test has failed
// If we expect an error (correct == false) but we don't get one, the test has failes
// In all other cases, the test is successful !
if err != nil && correct {
t.Errorf("expected no errors but got one: %v", err)
} else if err == nil && !correct {
t.Errorf("expected an error but didn't get one !")
}
}
}
// Create the sub functions (those will be the correct and incorrect version of this test)
sub := func(data map[string][]byte, correct bool) func(t *testing.T) {
return func(t *testing.T) {
// Declare this test to be run in parallel
t.Parallel()
// If we have no data, we skip
if len(data) == 0 {
t.Skip("no data provided, skipping...")
}
// For all files provided
for name, datum := range data {
// Get the run function
rfunc := rgen(datum, correct)
// Run !
t.Run(name, rfunc)
}
}
}
// Run !
t.Run("correct", sub(data.correct, true))
t.Run("incorrect", sub(data.incorrect, false))
}

9
types/company.go Normal file
View File

@ -0,0 +1,9 @@
package types
// A Company is a provider of transport
// Example: the RATP in Paris
// See http://doc.navitia.io/#public-transport-objects
type Company struct {
ID string `json:"id"` // Identifier of the company
Name string `json:"name"` // Name of the company
}

280
types/container.go Normal file
View File

@ -0,0 +1,280 @@
package types
import (
"encoding/json"
"fmt"
"sync"
"github.com/pkg/errors"
)
// these are the types that can be embedded.
const (
EmbeddedStopArea = "stop_area" // This is a Place & a PT Object
EmbeddedPOI = "poi" // This is a place
EmbeddedAddress = "address" // This is a place
EmbeddedStopPoint = "stop_point" // This is a place
EmbeddedAdmin = "administrative_region" // This is a place
EmbeddedLine = "line" // This is a PT Object
EmbeddedRoute = "route" // This is a PT Object
EmbeddedNetwork = "network" // This is a PT Object
EmbeddedCommercialMode = "commercial_mode" // This is a PT Object
EmbeddedTrip = "trip" // This is a PT Object
)
// EmbeddedTypes lists all the possible embedded types you can find in a Container
var EmbeddedTypes = [...]string{
EmbeddedStopArea,
EmbeddedPOI,
EmbeddedAddress,
EmbeddedStopPoint,
EmbeddedAdmin,
EmbeddedLine,
EmbeddedRoute,
EmbeddedNetwork,
EmbeddedCommercialMode,
EmbeddedTrip,
}
// embeddedTypesPlace stores a list of embedded types you can find in a container containing a Place.
var embeddedTypesPlace = [...]string{
EmbeddedStopArea,
EmbeddedPOI,
EmbeddedAddress,
EmbeddedStopPoint,
EmbeddedAdmin,
}
// embeddedTypesPTObject stores a list of embedded types you can find in a container containing a PTObject.
var embeddedTypesPTObject = [...]string{
EmbeddedStopArea,
EmbeddedLine,
EmbeddedRoute,
EmbeddedNetwork,
EmbeddedCommercialMode,
EmbeddedTrip,
}
// An Object is what is contained by a Container
type Object interface{}
// A Container holds an Object, which can be a Place or a PT Object
type Container struct {
ID ID `json:"id"`
Name string `json:"name"`
EmbeddedType string `json:"embedded_type"`
Quality int `json:"quality"`
embeddedJSON json.RawMessage
// embeddedObject acts as a cache, it is the only element guarded by the RWMutex
embeddedObject Object
// If multiple goroutines try to access embeddedObject while one is writing it, results are undefined.
// So we guard against it through a mutex.
mu *sync.RWMutex
}
// IsPlace returns true if the container's content is a Place
func (c *Container) IsPlace() bool {
t := c.EmbeddedType
return t == EmbeddedStopArea ||
t == EmbeddedPOI ||
t == EmbeddedAddress ||
t == EmbeddedStopPoint ||
t == EmbeddedAdmin
}
// IsPTObject returns true if the container's content is a PTObject
func (c *Container) IsPTObject() bool {
t := c.EmbeddedType
return t == EmbeddedStopArea ||
t == EmbeddedLine ||
t == EmbeddedRoute ||
t == EmbeddedNetwork ||
t == EmbeddedCommercialMode ||
t == EmbeddedTrip
}
// ErrInvalidContainer is returned after a check on a Container
type ErrInvalidContainer struct {
// If the Container has a zero ID.
NoID bool
// If the PlaceContainer has an EmbeddedType yet non-empty embedded content.
NoEmbeddedType bool
// If the PlaceContainer has an unknown EmbeddedType
UnknownEmbeddedType bool
}
// Error satisfies the error interface
func (err ErrInvalidContainer) Error() string {
// Count the number of anomalies
var anomalies uint
msg := "Error: Invalid non-empty PlaceContainer (%d anomalies):"
if err.NoID {
msg += "\n\tNo ID specified"
anomalies++
}
if err.NoEmbeddedType {
msg += "\n\tEmpty EmbeddedType yet non-empty embedded content"
anomalies++
}
if err.UnknownEmbeddedType {
msg += "\n\tUnknown EmbeddedType"
anomalies++
}
return fmt.Sprintf(msg, anomalies)
}
// Empty returns true if the container is empty (zero value)
func (c *Container) Empty() bool {
return c.ID == "" && c.Name == "" && c.EmbeddedType == "" && c.Quality == 0 && len(c.embeddedJSON) == 0 && c.embeddedObject == nil
}
// Check checks the validity of the Container. Returns an ErrInvalidContainer.
//
// An empty Container is valid. But those cases aren't:
// - If the Container has an empty ID.
// - If the Container has an empty EmbeddedType & a non-empty embedded types inside.
// - If the Container has an unknown EmbeddedType.
func (c *Container) Check() error {
// Check if the container is empty
if c.Empty() {
return nil
}
// Create the error to be populated
err := ErrInvalidContainer{}
// Check for zero ID
err.NoID = c.ID == ""
// Check if the embedded type is empty & there is a non-empty embedded content inside, that's an error
if c.EmbeddedType == "" && (len(c.embeddedJSON) != 0 || c.embeddedObject != nil) {
err.NoEmbeddedType = true
return err
} else if c.EmbeddedType == "" { // Else, if the embedded type indicator is empty, the rest is useless
return nil
}
// Else, check if the declared EmbeddedType is known.
var known bool
for _, ket := range EmbeddedTypes {
if c.EmbeddedType == ket {
known = true
break
}
}
err.UnknownEmbeddedType = !known
// Check if there's any change
emptyErr := ErrInvalidContainer{}
if err != emptyErr {
return err
}
return nil
}
// Object returns the Object contained in a Container.
// If the Container is empty, Object returns an error.
// Check() is run on the Container.
func (c *Container) Object() (Object, error) {
if c.EmbeddedType == "" {
return nil, nil
}
// If we already have an embedded object, return it
c.mu.RLock()
o := c.embeddedObject
c.mu.RUnlock()
if o != nil {
return o, nil
}
// Create the receiver
var obj Object
// Switch through
switch c.EmbeddedType {
case EmbeddedStopArea:
obj = &StopArea{}
case EmbeddedPOI:
obj = &POI{}
case EmbeddedAddress:
obj = &Address{}
case EmbeddedStopPoint:
obj = &StopPoint{}
case EmbeddedAdmin:
obj = &Admin{}
case EmbeddedLine:
obj = &Line{}
case EmbeddedRoute:
obj = &Route{}
case EmbeddedNetwork:
obj = &Network{}
case EmbeddedCommercialMode:
obj = &CommercialMode{}
case EmbeddedTrip:
obj = &Trip{}
default:
return nil, errors.Errorf("no known embedded type indicated (we have \"%s\"), can't return a place !", c.EmbeddedType)
}
// Unmarshal into the receiver
err := json.Unmarshal(c.embeddedJSON, obj)
if err != nil {
return nil, errors.Wrapf(err, "couldn't unmarshal the embedded type (%s)", c.EmbeddedType)
}
// Let's add it to the container
c.mu.Lock()
c.embeddedObject = obj
c.mu.Unlock()
// Let's return it
return obj, nil
}
// Place returns the Place contained in the container if that is what's inside
//
// If the Object isn't a Place or the Container is empty or invalid, Place returns an error
func (c *Container) Place() (Place, error) {
// Check if its a Place
if !c.IsPlace() {
return nil, errors.Errorf("container's content isn't a Place")
}
// Return it then
obj, err := c.Object()
if err != nil {
return nil, err
}
// Type assert
return obj.(Place), nil
}
// PTObject returns the PTObject contained in the container if that is what's inside
//
// If the Object isn't a PTObject or the Container is empty or invalid, Place returns an error
func (c *Container) PTObject() (PTObject, error) {
// Check if its a Place
if !c.IsPTObject() {
return nil, errors.Errorf("container's content isn't a PTObject")
}
// Return it then
obj, err := c.Object()
if err != nil {
return nil, err
}
// Type assert
return obj.(PTObject), nil
}

21
types/container_fuzz.go Normal file
View File

@ -0,0 +1,21 @@
// +build gofuzz
package types
func FuzzContainer(data []byte) int {
c := &Container{}
// Let's unmarshal, this is not our job so "bleh"
err := c.UnmarshalJSON(data)
if err != nil {
return 0
}
// Let's check it !
err = c.Check()
if err != nil {
return 0
}
return 1
}

57
types/container_json.go Normal file
View File

@ -0,0 +1,57 @@
package types
import (
"encoding/json"
"sync"
"github.com/pkg/errors"
)
// UnmarshalJSON satisfies the json.Unmarshaller interface
func (c *Container) UnmarshalJSON(b []byte) error {
// Set up a mutex
c.mu = &sync.RWMutex{}
// Unmarshal into a map
data := map[string]json.RawMessage{}
err := json.Unmarshal(b, &data)
if err != nil {
return errors.Wrap(err, "Couldn't unmarshal into a map")
}
// Create the error generator
gen := unmarshalErrorMaker{"Container", b}
// From a map, extract the ID, Name & EmbeddedType
if id, ok := data["id"]; ok {
err := json.Unmarshal(id, &c.ID)
if err != nil {
return gen.err(err, "ID", "id", id, "error while unmarshalling")
}
}
if name, ok := data["name"]; ok {
err := json.Unmarshal(name, &c.Name)
if err != nil {
return gen.err(err, "Name", "name", name, "error while unmarshalling")
}
}
if embeddedType, ok := data["embedded_type"]; ok {
err := json.Unmarshal(embeddedType, &c.EmbeddedType)
if err != nil {
return gen.err(err, "EmbeddedType", "embedded_type", embeddedType, "error while unmarshalling")
}
}
if quality, ok := data["quality"]; ok {
err := json.Unmarshal(quality, &c.Quality)
if err != nil {
return gen.err(err, "Quality", "quality", quality, "error while unmarshalling")
}
}
// Now, assign the embedded content to the Container
if embedded, ok := data[c.EmbeddedType]; ok {
c.embeddedJSON = embedded
}
return nil
}

259
types/container_test.go Normal file
View File

@ -0,0 +1,259 @@
package types
import (
"encoding/json"
"fmt"
"testing"
)
var containers map[string]*Container
// loadContainers loads the containers in their final form for testing
func loadContainers() error {
// Get the input
corpus := testData["container"].correct
if len(corpus) == 0 {
return nil
}
cs := make(map[string]*Container, len(corpus))
// For each of them, unmarshal and add to containers
for name, datum := range corpus {
c := &Container{}
err := c.UnmarshalJSON(datum)
if err != nil {
return fmt.Errorf("error while unmarshalling: %v", err)
}
cs[name] = c
}
containers = cs
return nil
}
// TestContainer_Object_NoCompare tests the Container.Object method
func TestContainer_Object_NoCompare(t *testing.T) {
// Get the input
data := containers
if len(data) == 0 {
t.Skip("No data to test")
}
// Create the run function generator, allowing us to run it in parallel
rgen := func(c *Container) func(t *testing.T) {
return func(t *testing.T) {
// Get the object
obj, err := c.Object()
if err != nil {
t.Errorf("Error while calling .Object(): %v", err)
}
// Log it
t.Logf("Object: %#v", obj)
}
}
// For each of them, let's run a subtest
for name, datum := range data {
// Create the run function
rfunc := rgen(datum)
// Run !
t.Run(name, rfunc)
}
}
// TestContainer_Check_NoCompare tests the Container.Check method
func TestContainer_Check_NoCompare(t *testing.T) {
// Get the input
data := containers
if len(data) == 0 {
t.Skip("No data to test")
}
// Create the run function generator, allowing us to run it in parallel
rgen := func(c *Container) func(t *testing.T) {
return func(t *testing.T) {
err := c.Check()
if err != nil {
t.Errorf("Check gave us invalid results: %v", err)
}
}
}
// For each of them, let's run a subtest
for name, datum := range data {
// Create the run function
rfunc := rgen(datum)
// Run !
t.Run(name, rfunc)
}
}
// BenchmarkContainer_UnmarshalJSON benchmarks Container.UnmarshalJSON through benchmarks
func BenchmarkContainer_UnmarshalJSON(b *testing.B) {
// Get the bench data
data := testData["container"].bench
if len(data) == 0 {
b.Skip("No data to test")
}
// Run function generator, allowing parallel run
// Returns three functions: one without .Object() being called, one with, one one with only the call to .Object being recorded
runGen := func(in []byte) (without func(*testing.B), with func(*testing.B), only func(*testing.B)) {
without = func(b *testing.B) {
for i := 0; i < b.N; i++ {
// Unmarshal a Journey
c := &Container{}
_ = c.UnmarshalJSON(in)
}
}
with = func(b *testing.B) {
for i := 0; i < b.N; i++ {
// Unmarshal a Journey
c := &Container{}
_ = c.UnmarshalJSON(in)
_, _ = c.Object()
}
}
only = func(b *testing.B) {
for i := 0; i < b.N; i++ {
// Unmarshal a Journey
b.StopTimer()
c := &Container{}
_ = c.UnmarshalJSON(in)
b.StartTimer()
_, _ = c.Object()
}
}
return
}
// Loop over all corpus
for name, datum := range data {
// Get run function
without, with, only := runGen(datum)
// Run it !
b.Run(name+"_without", without)
b.Run(name+"_with", with)
b.Run(name+"_only", only)
}
}
// BenchmarkContainer_Check benchmarks Container.Check through subbenchmarks
func BenchmarkContainer_Check(b *testing.B) {
// Get the bench data
data := testData["container"].bench
if len(data) == 0 {
b.Skip("No data to test")
}
// Run function generator, allowing parallel run
runGen := func(in Container) func(*testing.B) {
return func(b *testing.B) {
for i := 0; i < b.N; i++ {
// Call .Check
_ = in.Check()
}
}
}
// Loop over all corpus
for name, datum := range data {
c := Container{}
err := json.Unmarshal(datum, &c)
if err != nil {
b.Errorf("Error while unmarshalling: %v", err)
}
// Get run function
runFunc := runGen(c)
// Run it !
b.Run(name, runFunc)
}
}
// TestContainer_IsXXX tests (*Container).IsPlace and (*Container).IsPTObject
func TestContainer_IsXXX(t *testing.T) {
t.Run("IsPlace", func(t *testing.T) {
for _, et := range embeddedTypesPlace {
c := &Container{EmbeddedType: et}
if !c.IsPlace() {
t.Errorf("IsPlace for embedded type %s: expected true got false", et)
}
}
for _, et := range embeddedTypesPTObject {
if et != EmbeddedStopArea {
c := &Container{EmbeddedType: et}
if c.IsPlace() {
t.Errorf("IsPlace for embedded type %s: expected false got true", et)
}
}
}
})
t.Run("IsPTObject", func(t *testing.T) {
for _, et := range embeddedTypesPTObject {
c := &Container{EmbeddedType: et}
if !c.IsPTObject() {
t.Errorf("IsPTObject for embedded type %s: expected true got false", et)
}
}
for _, et := range embeddedTypesPlace {
if et != EmbeddedStopArea {
c := &Container{EmbeddedType: et}
if c.IsPTObject() {
t.Errorf("IsPTObject for embedded type %s: expected false got true", et)
}
}
}
})
}
// TestContainer_Empty tests that (*Container).Empty reports correctly whether or not the container is truly empty
func TestContainer_Empty(t *testing.T) {
emptyContainer := Container{}
nonEmptyContainers := []Container{
{
ID: "test",
},
{
Name: "test",
},
{
EmbeddedType: "test",
},
{
Quality: 10,
},
{
embeddedObject: new(Object),
},
{
embeddedJSON: json.RawMessage("that's not very raw"),
},
}
// If the empty container isn't reported as such, error
if !emptyContainer.Empty() {
t.Errorf("Calling (*Container).Empty on an empty container returned with false when we expected true")
}
// Iterate through the test non-empty containers
for _, c := range nonEmptyContainers {
if c.Empty() {
t.Errorf("Calling (*Container).Empty on a non-empty container returned true when we expected false. Container: %#v", c)
}
}
}

51
types/coord.go Normal file
View File

@ -0,0 +1,51 @@
package types
import (
"encoding/json"
"fmt"
"strconv"
)
// Coordinates code for coordinates used throughout the API.
// This is the Go representation of "Coordinates". It implements Place.
// See http://doc.navitia.io/#standard-objects.
type Coordinates struct {
Longitude float64 `json:"lon"`
Latitude float64 `json:"lat"`
}
// jsonCoordinates define the JSON implementation of Coordinates types
type jsonCoordinates struct {
Latitude string `json:"lat"`
Longitude string `json:"lon"`
}
// ID formats coordinates for use in queries as an ID.
func (c Coordinates) ID() ID {
return ID(fmt.Sprintf("%3.3f;%3.3f", c.Longitude, c.Latitude))
}
// UnmarshalJSON implements json.Unmarshaller for a Coordinates
func (c *Coordinates) UnmarshalJSON(b []byte) error {
var data jsonCoordinates
err := json.Unmarshal(b, &data)
if err != nil {
return fmt.Errorf("error while unmarshalling Coordinates types : %w", err)
}
// Create the error generator
gen := unmarshalErrorMaker{"Coordinates", b}
// Now parse the values
c.Longitude, err = strconv.ParseFloat(data.Longitude, 64)
if err != nil {
return gen.err(err, "Longitude", "lon", data.Longitude, "error in strconv.ParseFloat")
}
c.Latitude, err = strconv.ParseFloat(data.Latitude, 64)
if err != nil {
return gen.err(err, "Latitude", "lat", data.Latitude, "error in strconv.ParseFloat")
}
return nil
}

18
types/departure.go Normal file
View File

@ -0,0 +1,18 @@
package types
type Departure struct {
DisplayInformations Display `json:"display_informations"`
StopPoint StopPoint `json:"stop_point"`
Route Route `json:"route"`
Links []Link `json:"links"`
StopDateTime
}
type StopDateTime struct {
Links []Link `json:"links"`
ArrivalDateTime string `json:"arrival_date_time"`
DepartureDateTime string `json:"departure_date_time"`
BaseArrivalDateTime string `json:"base_arrival_date_time"`
BaseDepartureDateTime string `json:"base_departure_date_time"`
DataFreshness string `json:"data_freshness"`
}

89
types/display.go Normal file
View File

@ -0,0 +1,89 @@
package types
import (
"encoding/json"
"fmt"
"image/color"
)
// A Display holds informations useful to display.
type Display struct {
Headsign string `json:"headsign"` // The headsign associated with the object
Network string `json:"network"` // The name of the belonging network
Direction string `json:"direction"` // A direction to take
CommercialMode ID `json:"commercial_mode"` // The commercial mode in ID Form
PhysicalMode ID `json:"physical_mode"` // The physical mode in ID Form
Label string `json:"label"` // The label of the object
Color color.Color `json:"color"` // Hexadecimal color of the line
TextColor color.Color `json:"text_color"` // The text color for this section
Code string `json:"code"` // The code of the line
Description string `json:"description"` // Description
Equipments []Equipment `json:"equipments"` // Equipments on this object
Name string `json:"name"` // Name of object
TripShortName string `json:"trip_short_name"` // TripShoerName short name of the current trip
}
// jsonDisplay define the JSON implementation of Display types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonDisplay struct {
// Pointers to the corresponding real values
Headsign *string `json:"headsign"`
Network *string `json:"network"`
Direction *string `json:"direction"`
CommercialMode *ID `json:"commercial_mode"`
PhysicalMode *ID `json:"physical_mode"`
Label *string `json:"label"`
Code *string `json:"code"`
Description *string `json:"description"`
Equipments *[]Equipment `json:"equipments"`
// Values to process
Color string `json:"color"`
TextColor string `json:"text_color"`
}
// UnmarshalJSON implements json.Unmarshaller for a Display
func (d *Display) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
// We define some of the value as pointers to the real values, allowing us to bypass copying in cases where we don't need to process the data
data := &jsonDisplay{
Headsign: &d.Headsign,
Network: &d.Network,
Direction: &d.Direction,
CommercialMode: &d.CommercialMode,
PhysicalMode: &d.PhysicalMode,
Label: &d.Label,
Code: &d.Code,
Description: &d.Description,
Equipments: &d.Equipments,
}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling Display: %w", err)
}
// Create the error generator
gen := unmarshalErrorMaker{"Display", b}
// Now process the values
// We expect a color string length of 6 because it should be coded in hexadecimal
if str := data.Color; len(str) == 6 {
clr, err := parseColor(str)
if err != nil {
return gen.err(err, "Color", "color", str, "error in parseColor")
}
d.Color = clr
}
if str := data.TextColor; len(str) == 6 {
clr, err := parseColor(str)
if err != nil {
return gen.err(err, "TextColor", "text_color", str, "error in parseColor")
}
d.TextColor = clr
}
return nil
}

137
types/disruption.go Normal file
View File

@ -0,0 +1,137 @@
package types
import (
"encoding/json"
"fmt"
"time"
)
// Effect codes for known journey status information
// For example, reduced service, detours or moved stops.
//
// See https://developers.google.com/transit/gtfs-realtime/reference/Effect for more information
type Effect string
// JourneyStatusXXX are known JourneyStatuse
const (
// Service suspended.
EffectNoService Effect = "NO_SERVICE"
// Service running at lowered capacity.
JourneyStatusReducedService = "REDUCED_SERVICE"
// Service running but with substantial delays expected.
JourneyStatusSignificantDelay = "SIGNIFICANT_DELAY"
// Service running on alternative routes to avoid problem.
JourneyStatusDetour = "DETOUR"
// Service above normal capacity.
JourneyStatusAdditionalService = "ADDITIONAL_SERVICE"
// Service different from normal capacity.
JourneyStatusModifiedService = "MODIFIED_SERVICE"
// Miscellaneous, undefined Effect.
JourneyStatusOtherEffect = "OTHER_EFFECT"
// Default setting: Undetermined or Effect not known.
JourneyStatusUnknownEffect = "UNKNOWN_EFFECT"
// Stop not at previous location or stop no longer on route.
JourneyStatusStopMoved = "STOP_MOVED"
)
type DisruptionStatus string
const (
StatusPast DisruptionStatus = "past"
StatusActive = "active"
StatusFuture = "future"
)
// A Disruption reports the specifics of a Disruption
type Disruption struct {
ID ID `json:"id"` // ID of the Disruption
// State of the disruption.
// The state is computed using the application_periods of the disruption and the current time of the query.
// It can be either "Past", "Active" or "Future"
Status DisruptionStatus `json:"status"`
Tags []string `json:"tags"`
InputDisruptionID ID // For traceability, ID of original input disruption
InputImpactID ID // For traceability: Id of original input impact
Severity Severity `json:"severity"` // Severity gives some categorization element
Periods []Period // Dates where the current disruption is active
Messages []Message // Text to provide to the traveller
LastUpdated time.Time // Last Update of that disruption
Impacted []ImpactedObject `json:"impacted_stops"` // Objects impacted
Cause string // The cause of that disruption
Category string // The category of the disruption, optional.
DisruptionID string `json:"disruption_id"`
}
// jsonDisruption define the JSON implementation of Disruption types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonDisruption struct {
// The references
ID *ID `json:"id"`
Status *DisruptionStatus `json:"status"`
Tags *[]string `json:"tags"`
InputDisruptionID *ID `json:"disruption_id"`
InputImpactID *ID `json:"impact_id"`
Severity *Severity `json:"severity"`
Periods *[]Period `json:"application_periods"`
Messages *[]Message `json:"messages"`
Impacted *[]ImpactedObject `json:"impacted_objects"`
Cause *string `json:"cause"`
Category *string `json:"category"`
// Those we will process
LastUpdated string `json:"updated_at"`
}
type PTObjectDisruptions struct {
EmbeddedType string `json:"embedded_type"`
ID string `json:"id"`
Quality int `json:"quality"`
Name string `json:"name"`
Trip Trip `json:"trip"`
}
// UnmarshalJSON implements json.Unmarshaller for a Disruption
func (d *Disruption) UnmarshalJSON(b []byte) error {
data := &jsonDisruption{
ID: &d.ID,
Status: &d.Status,
Tags: &d.Tags,
InputDisruptionID: &d.InputDisruptionID,
InputImpactID: &d.InputImpactID,
Severity: &d.Severity,
Periods: &d.Periods,
Messages: &d.Messages,
Impacted: &d.Impacted,
Cause: &d.Cause,
Category: &d.Category,
}
// Let's create the error generator
gen := unmarshalErrorMaker{"Disruption", b}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling Disruption: %w", err)
}
// Now we process the Update time
d.LastUpdated, err = parseDateTime(data.LastUpdated)
if err != nil {
return gen.err(err, "LastUpdated", "updated_at", data.LastUpdated, "parseDateTime failed")
}
// Finished !
return nil
}

16
types/disruption_test.go Normal file
View File

@ -0,0 +1,16 @@
package types
import (
"reflect"
"testing"
)
// Test_Disruption_Unmarshal tests unmarshalling for Disruption.
// As the unmarshalling is done in-house, this allows us to check that the custom UnmarshalJSON function correctly
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func Test_Disruption_Unmarshal(t *testing.T) {
testUnmarshal(t, testData["disruption"], reflect.TypeOf(Disruption{}))
}

48
types/equipment.go Normal file
View File

@ -0,0 +1,48 @@
package types
// An Equipment codes for specific equipment the public transport object has
type Equipment string
// EquipmentWheelchairAccessibility are known equipments
const (
EquipmentWheelchairAccessibility Equipment = "has_wheelchair_accessibility"
EquipmentBikeAccepted Equipment = "has_bike_accepted"
EquipmentAirConditioned Equipment = "has_air_conditioned"
EquipmentVisualAnnouncement Equipment = "has_visual_announcement"
EquipmentAudibleAnnouncement Equipment = "has_audible_announcement"
EquipmentAppropriateEscort Equipment = "has_appropriate_escort"
EquipmentAppropriateSignage Equipment = "has_appropriate_signage"
EquipmentSchoolVehicle Equipment = "has_school_vehicle"
EquipmentWheelchairBoarding Equipment = "has_wheelchair_boarding"
EquipmentSheltered Equipment = "has_sheltered"
EquipmentElevator Equipment = "has_elevator"
EquipmentEscalator Equipment = "has_escalator"
EquipmentBikeDepot Equipment = "has_bike_depot"
)
// knownEquipments lists all the known equipments
var knownEquipments = [...]Equipment{
EquipmentWheelchairAccessibility,
EquipmentBikeAccepted,
EquipmentAirConditioned,
EquipmentVisualAnnouncement,
EquipmentAudibleAnnouncement,
EquipmentAppropriateEscort,
EquipmentAppropriateSignage,
EquipmentSchoolVehicle,
EquipmentWheelchairBoarding,
EquipmentSheltered,
EquipmentElevator,
EquipmentEscalator,
EquipmentBikeDepot,
}
// Known reports whether an equipment is known
func (eq Equipment) Known() bool {
for _, k := range knownEquipments {
if eq == k {
return true
}
}
return false
}

6
types/exception.go Normal file
View File

@ -0,0 +1,6 @@
package types
type Exception struct {
Type string `json:"type"`
Datetime string `json:"datetime"`
}

54
types/fare.go Normal file
View File

@ -0,0 +1,54 @@
package types
import (
"encoding/json"
"github.com/pkg/errors"
"golang.org/x/text/currency"
)
// Fare is the fare of some thing
type Fare struct {
Total currency.Amount
Found bool
}
// UnmarshalJSON implements json.Unmarshaller for a Fare
func (f *Fare) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
// We define some of the value as pointers to the real values, allowing us to bypass copying in cases where we don't need to process the data
data := &struct {
Found *bool `json:"found"`
Cost struct {
Value string `json:"value"`
Currency string `json:"currency"`
} `json:"cost"`
}{
Found: &f.Found,
}
// Now unmarshall the raw data into the analogous structure
if err := json.Unmarshal(b, data); err != nil {
return errors.Wrap(err, "Error while unmarshalling journey")
}
// Let's create the error generator
gen := unmarshalErrorMaker{"Fare", b}
// Let's convert the cost now
// If we have no defined fare, let's skip that part
if data.Cost.Value == "" || data.Cost.Currency == "" {
return nil
}
// First get the currency unit
unit, err := currency.ParseISO(data.Cost.Currency)
if err != nil {
return gen.err(err, "Total", "cost.currency", data.Cost.Currency, "error while retrieving currency unit via currency.ParseISO")
}
// Now let's create the correct amount
f.Total = unit.Amount(data.Cost.Value)
return nil
}

5
types/fareZone.go Normal file
View File

@ -0,0 +1,5 @@
package types
type FareZone struct {
Name string `json:"name"`
}

43
types/fuzz.sh Executable file
View File

@ -0,0 +1,43 @@
#!/bin/bash
shopt -s extglob
declare -A functionNames
functionNames=(["FuzzJourney"]="journey" ["FuzzPlaceCountainer"]="place")
echo "Functions that will be built:"
printf "\t- %s\n" "${!functionNames[@]}"
workdirPath="/tmp/fuzz"
echo "Creating global workdir: $workdirPath"
mkdir $workdirPath
for i in "${!functionNames[@]}"
do
path="$workdirPath/$i"
mkdir $path
mkdir "$path/corpus"
binpath="$path/$i.zip"
corpuspath="./testdata/${functionNames[$i]}"
echo "Copying corpus for $i from $corpuspath"
cp $corpuspath/known/* "$path/corpus/"
cp $corpuspath/corpus/* "$path/corpus/"
echo "Building $i"
go-fuzz-build -func $i -o $binpath github.com/aabizri/gonavitia/types
echo "Running $i ($binpath)"
go-fuzz -bin $binpath -workdir=$path
echo "Copying back corpus from $corpuspath"
destination="./testdata/${functionNames[$i]}/corpus"
rsync --exclude="*.json" $path/corpus/* $destination/
echo "Copying crashers"
destination="./testdata/${functionNames[$i]}/crasher"
commit=`git rev-parse HEAD`
for j in $path/crashers/*
do
filename=$commit-${j##*/}
cp $j $destination/$filename
done
done

50
types/id.go Normal file
View File

@ -0,0 +1,50 @@
package types
import (
"strings"
"github.com/pkg/errors"
)
// An ID is used throughout the library, it is something used by the navitia API and useful to communicate with it.
type ID string
// Check for ID validity
func (id ID) Check() error {
if len(id) == 0 {
return errors.Errorf("ID invalid: an empty string \"\" is not a valid ID")
}
return nil
}
// typeNames stores navitia-side name of types that may appear in IDs
var typeNames = map[string]bool{
"network": true,
"line": true,
"route": true,
"stop_area": true,
"commercial_mode": true,
"physical_mode": true,
"company": true,
"admin": true,
"stop_point": true,
}
// Type gets the type of object this ID refers to.
//
// Possible types: network, line, route, stop_area, commercial_mode, physical_mode, company, admin, stop_point.
//
// This is just guessing, if no type is found, type returns an empty string.
func (id ID) Type() string {
splitted := strings.Split(string(id), ":")
if len(splitted) == 0 {
return ""
}
possible := splitted[0]
if typeNames[possible] {
return possible
}
return ""
}

11
types/id_test.go Normal file
View File

@ -0,0 +1,11 @@
package types
import "testing"
// TestIDCheck checks if ID.Check returns an error when given an empty ID
func TestIDCheck(t *testing.T) {
id := ID("")
if id.Check() == nil {
t.Errorf("Received no error even though we expect one")
}
}

13
types/impactedObject.go Normal file
View File

@ -0,0 +1,13 @@
package types
// An ImpactedObject describes a PTObject impacted by a Disruption with some additional info.
type ImpactedObject struct {
// The impacted public transport object
Object Container `json:"pt_object"`
// Only for line section impact, the impacted section
ImpactedSection ImpactedSection `json:"impacted_section"`
// Only for Trip delay, the list of delays, stop by stop
ImpactedStops []ImpactedStop `json:"impacted_stops"`
}

9
types/impactedSection.go Normal file
View File

@ -0,0 +1,9 @@
package types
// An ImpactedSection records the impact to a section
type ImpactedSection struct {
// The start of the disruption, spatially
From Container `json:"from"`
// Until this point
To Container `json:"to"`
}

42
types/impactedStop.go Normal file
View File

@ -0,0 +1,42 @@
package types
// An ImpactedStop records the impact to a stop
type ImpactedStop struct {
// The impacted stop point of the trip
Point StopPoint `json:"stop_point"`
// New departure hour (format HHMMSS) of the trip on this stop point
NewDeparture string
// New arrival hour (format HHMMSS) of the trip on this stop point
NewArrival string
// Base departure hour (format HHMMSS) of the trip on this stop point
BaseDeparture string
// Base arrival hour (format HHMMSS) of the trip on this stop point
BaseArrival string
// Cause of the modification
Cause string `json:"cause"`
// Effect on that StopPoint
// Can be "added", "deleted", "delayed"
Effect string
AmendedArrivalTime string `json:"amended_arrival_time"`
StopTimeEffect string `json:"stop_time_effect"`
DepartureStatus string `json:"departure_status"`
IsDetour bool `json:"is_detour"`
AmendedDepartureTime string `json:"amended_departure_time"`
BaseArrivalTime string `json:"base_arrival_time"`
BaseDepartureTime string `json:"base_departure_time"`
ArrivalStatus string `json:"arrival_status"`
}

10
types/isochrone.go Normal file
View File

@ -0,0 +1,10 @@
package types
import "github.com/paulmach/go.geojson"
// An Isochrone is sent back by the /isochrones service, it gives you a multi-polygon geojson response which represent a same time travel zone.
//
// See https://en.wikipedia.org/wiki/Isochrone_map for what is an isochrone.
//
// See http://doc.navitia.io/#isochrones-currently-in-beta
type Isochrone geojson.Geometry

9
types/journeyPattern.go Normal file
View File

@ -0,0 +1,9 @@
package types
// JourneyPattern A journey pattern is an ordered list of stop points.
// Two vehicles that serve exactly the same stop points in
// exactly the same order belong to to the same journey pattern.
type JourneyPattern struct {
ID string
Name string
}

195
types/journeys.go Normal file
View File

@ -0,0 +1,195 @@
package types
import (
"encoding/json"
"fmt"
"strconv"
"time"
)
// A JourneyQualification qualifies a Journey, see const declaration.
type JourneyQualification string
// JourneyXXX qualify journeys
const (
JourneyBest JourneyQualification = "best"
JourneyRapid JourneyQualification = "rapid"
JourneyComfort JourneyQualification = "comfort"
JourneyCar JourneyQualification = "car"
JourneyLessWalk JourneyQualification = "less_fallback_walk"
JourneyLessBike JourneyQualification = "less_fallback_bike"
JourneyLessBikeShare JourneyQualification = "less_fallback_bss"
JourneyFastest JourneyQualification = "fastest"
JourneyNoPTWalk JourneyQualification = "non_pt_walk"
JourneyNoPTBike JourneyQualification = "non_pt_bike"
JourneyNoPTBikeShare JourneyQualification = "non_pt_bss"
)
// JourneyQualifications is a user-friendly slice of all journey qualification
// As it might be used in requests, this is exported
var JourneyQualifications = []JourneyQualification{
JourneyBest,
JourneyRapid,
JourneyComfort,
JourneyCar,
JourneyLessWalk,
JourneyLessBike,
JourneyLessBikeShare,
JourneyFastest,
JourneyNoPTWalk,
JourneyNoPTBike,
JourneyNoPTBikeShare,
}
// A Journey holds information about a possible journey
type Journey struct {
Duration time.Duration
Transfers uint
Departure time.Time
Requested time.Time
Arrival time.Time
CO2Emissions CO2Emissions
Sections []Section
From Container
To Container
Type JourneyQualification
Fare Fare
// Status from the whole journey taking into acount the most disturbing information retrieved on every object used
Status Effect
}
// jsonJourney define the JSON implementation of Journey types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonJourney struct {
Duration int64 `json:"duration"`
Transfers *uint `json:"nb_transfers"`
Departure string `json:"departure_date_time"`
Requested string `json:"requested_date_time"`
Arrival string `json:"arrival_date_time"`
Sections *[]Section `json:"sections"`
From *Container `json:"from"`
To *Container `json:"to"`
Type *JourneyQualification `json:"type"`
Fare *Fare `json:"fare"`
Status *Effect `json:"status"`
}
// CO2Emissions holds how much CO2 is emitted.
type CO2Emissions struct {
Unit string
Value float64
}
// jsonCO2Emissions define the JSON implementation of CO2Emissions types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonCO2Emissions struct {
Unit *string `json:"unit"`
Value string `json:"value"`
}
// TravelerType is a Traveler's type
// Defines speeds & accessibility values for different types of people
type TravelerType string
// The defined types of the api
const (
// A standard Traveler
TravelerStandard TravelerType = "standard"
// A slow walker
TravelerSlowWalker TravelerType = "slow_walker"
// A fast walker
TravelerFastWalker TravelerType = "fast_walker"
// A Traveler with luggage
TravelerWithLuggage TravelerType = "luggage"
// A Traveler in a wheelchair
TravelerInWheelchair TravelerType = "wheelchair"
)
// UnmarshalJSON implements json.Unmarshaller for a Journey.
// Behaviour:
// - If "from" is empty, then don't populate the From field.
// - Same for "to"
func (j *Journey) UnmarshalJSON(b []byte) error {
data := &jsonJourney{
Transfers: &j.Transfers,
Sections: &j.Sections,
From: &j.From,
To: &j.To,
Type: &j.Type,
Fare: &j.Fare,
Status: &j.Status,
}
// Now unmarshall the raw data into the analogous structure
if err := json.Unmarshal(b, data); err != nil {
return fmt.Errorf("error while unmarshalling Journey: %w", err)
}
// Let's create the error generator
gen := unmarshalErrorMaker{"Journey", b}
// As the given duration is in second, let's multiply it by one second to have the correct value
j.Duration = time.Duration(data.Duration) * time.Second
var err error
// For departure, requested and arrival, we use parseDateTime
j.Departure, err = parseDateTime(data.Departure)
if err != nil {
return gen.err(err, "Departure", "departure_date_time", data.Departure, "parseDateTime failed")
}
j.Requested, err = parseDateTime(data.Requested)
if err != nil {
return gen.err(err, "Requested", "requested_date_time", data.Requested, "parseDateTime failed")
}
j.Arrival, err = parseDateTime(data.Arrival)
if err != nil {
return gen.err(err, "Arrival", "arrival_date_time", data.Arrival, "parseDateTime failed")
}
return nil
}
// UnmarshalJSON implements json.Unmarshaller for CO2Emissions
func (c *CO2Emissions) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
// We define some of the value as pointers to the real values, allowing us to bypass copying in cases where we don't need to process the data
data := &jsonCO2Emissions{
Unit: &c.Unit,
}
// Now unmarshall the raw data into the analogous structure
if err := json.Unmarshal(b, data); err != nil {
return fmt.Errorf("error while unmarshalling CO2Emissions: %w", err)
}
// Let's create the error generator
gen := unmarshalErrorMaker{"CO2Emissions", b}
// Now parse the value
f, err := strconv.ParseFloat(data.Value, 64)
if err != nil {
return gen.err(err, "Value", "value", data.Value, "error in strconv.ParseFloat")
}
c.Value = f
return nil
}

15
types/journeys_fuzz.go Normal file
View File

@ -0,0 +1,15 @@
// +build gofuzz
package types
func FuzzJourney(data []byte) int {
j := &Journey{}
// Let's unmarshal
err := j.UnmarshalJSON(data)
if err != nil {
return 0
}
return 1
}

45
types/journeys_test.go Normal file
View File

@ -0,0 +1,45 @@
package types
import (
"reflect"
"testing"
)
// Test_Journey_Unmarshal tests unmarshalling for Journey.
// As the unmarshalling is done in-house, this allows us to check that the custom UnmarshalJSON function correctly
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func Test_Journey_Unmarshal(t *testing.T) {
testUnmarshal(t, testData["journey"], reflect.TypeOf(Journey{}))
}
// BenchmarkJourney_UnmarshalJSON benchmarks Journey unmarshalling via subbenchmarks
func BenchmarkJourney_UnmarshalJSON(b *testing.B) {
// Get the bench data
data := testData["journey"].bench
if len(data) == 0 {
b.Skip("No data to test")
}
// Run function generator, allowing parallel run
runGen := func(in []byte) func(*testing.B) {
return func(b *testing.B) {
for i := 0; i < b.N; i++ {
// Unmarshal a Journey
j := &Journey{}
_ = j.UnmarshalJSON(in)
}
}
}
// Loop over all corpus
for name, datum := range data {
// Get run function
runFunc := runGen(datum)
// Run it !
b.Run(name, runFunc)
}
}

110
types/json.go Normal file
View File

@ -0,0 +1,110 @@
// json.go provides types & functions for json unmarshalling
package types
import (
"fmt"
"strings"
"time"
"github.com/pkg/errors"
)
const (
// DateTimeFormat is the format used by the Navitia Api for use with time pkg.
DateTimeFormat string = "20060102T150405" // YYYYMMDDThhmmss
// DateFormat is when there is no time info
DateFormat string = "20060102"
)
// parseDateTime parses a time formatted under iso-date-time as indicated in the Navitia api.
// This is simply parsing a date formatted under the standard ISO 8601.
// If the given string is empty (i.e ""), then the zero value of time.Time will be returned
func parseDateTime(datetime string) (time.Time, error) {
// If there's no datetime given, just return the zero value
if datetime == "" || datetime == "not-a-date-time" {
return time.Time{}, nil
}
// If the datetime doesn't countain a "T", then it does not have time info
var format string
if strings.Contains(datetime, "T") {
format = DateTimeFormat
} else {
format = DateFormat
}
// Parse it
res, err := time.Parse(format, datetime)
if err != nil {
err = errors.Wrap(err, "parseDateTime: error while parsing datetime")
}
return res, err
}
// UnmarshalError is returned when unmarshalling fails
// It implements both error and github.com/pkg/errors's causer
type UnmarshalError struct {
// Type on which the unmarshaller where the error occurred works
Type string
// JSON Key where failure occurred
Key string
// Name of the key in package
Name string
// Value associated with the key
Value interface{}
// Message of the error
Message string
// Underlying error
Underlying error
// Full JSON data
JSON []byte
}
// Cause implements github.com/pkg/error's causer
func (err UnmarshalError) Cause() error {
return err.Underlying
}
// Error implements error
func (err UnmarshalError) Error() string {
msg := fmt.Sprintf(
"(*%s).UnmarshalJSON: Unmarshalling %s (json: \"%s\") with value \"%v\" failed",
err.Type,
err.Name,
err.Key,
err.Value)
if err.Message != "" {
msg += ": " + err.Message
}
if err.Underlying != nil {
msg += " [" + err.Cause().Error() + "]"
}
return msg
}
// unmarshalErrorer allows us to make better error messages
type unmarshalErrorMaker struct {
Type string
JSON []byte
}
// err creates a new UnmarshalError
func (gen unmarshalErrorMaker) err(underlyingErr error, name string, key string, value interface{}, message string) error {
return UnmarshalError{
Type: gen.Type,
Key: key,
Name: name,
Value: value,
Message: message,
Underlying: underlyingErr,
JSON: gen.JSON,
}
}

128
types/line.go Normal file
View File

@ -0,0 +1,128 @@
package types
import (
"encoding/json"
"fmt"
"image/color"
"strconv"
"github.com/pkg/errors"
)
// A Line codes for a public transit line.
// Warning: a Line isn't a route, it has no direction information, and can have several embranchments.
// See http://doc.navitia.io/#public-transport-objects.
type Line struct {
ID ID `json:"id"` // ID is the navitia identifier of the line, eg: "line:RAT:M6"
Name string `json:"name"` // Name of the line eg: "Nation - Charles de Gaule Etoile"
Code string `json:"code"` // Code is the codename of the line
Color color.Color `json:"color"` // Color of the Line, eg "FFFFFF"
// OpeningTime is the opening time of the line
OpeningTime struct {
Hours uint8 `json:"hours"`
Minutes uint8 `json:"minutes"`
Seconds uint8 `json:"seconds"`
} `json:"opening_time"`
// ClosingTime is the closing time of the line
ClosingTime struct {
Hours uint8 `json:"hours"`
Minutes uint8 `json:"minutes"`
Seconds uint8 `json:"seconds"`
} `json:"closing_time"`
Routes []Route `json:"routes"` // Routes contains the routes of the line
CommercialMode CommercialMode `json:"commercial_mode"` // CommercialMode of the line
PhysicalModes []PhysicalMode `json:"physical_modes"` // PhysicalModes of the line
}
// jsonLine define the JSON implementation of Line types.
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonLine struct {
ID *ID `json:"id"` // ID is the navitia identifier of the line, eg: "line:RAT:M6"
Name *string `json:"name"` // Name of the line eg: "Nation - Charles de Gaule Etoile"
Code *string `json:"code"` // Code is the codename of the line
Routes *[]Route `json:"routes"` // Routes contains the routes of the line
CommercialMode *CommercialMode `json:"commercial_mode"` // CommercialMode of the line
PhysicalModes *[]PhysicalMode `json:"physical_modes"` // PhysicalModes of the line
// Value to process
Color string `json:"color"` // Color of the Line, eg "FFFFFF"
OpeningTime string `json:"opening_time"` // OpeningTime is the opening time of the line
ClosingTime string `json:"closing_time"` // ClosingTime is the closing time of the line
}
// UnmarshalJSON implements json.Unmarshaller for a Line
func (l *Line) UnmarshalJSON(b []byte) error {
data := jsonLine{
ID: &l.ID,
Name: &l.Name,
Code: &l.Code,
Routes: &l.Routes,
CommercialMode: &l.CommercialMode,
PhysicalModes: &l.PhysicalModes,
}
if err := json.Unmarshal(b, &data); err != nil {
return fmt.Errorf("error while unmarshalling Line types : %w", err)
}
// Create the error generator
gen := unmarshalErrorMaker{"Line", b}
// Now process the values
// For Color: we expect a color string length of 6 because it should be coded in hexadecimal
if str := data.Color; len(str) == 6 {
clr, err := parseColor(str)
if err != nil {
return gen.err(err, "Color", "color", str, "error in parseColor")
}
l.Color = clr
}
// For OpeningTime and ClosingTime: we define a function to help us
parseTime := func(str string) (h, m, s uint8, err error) {
if len(str) != 6 {
err = errors.Errorf("time string not to standard: len=%d instead of 6", len(str))
return
}
h64, err := strconv.ParseUint(str[:2], 10, 8)
if err != nil {
err = errors.Wrap(err, "error while parsing hours")
return
}
m64, err := strconv.ParseUint(str[2:4], 10, 8)
if err != nil {
err = errors.Wrap(err, "error while parsing minutes")
return
}
s64, err := strconv.ParseUint(str[4:], 10, 8)
if err != nil {
err = errors.Wrap(err, "error while parsing seconds")
return
}
return uint8(h64), uint8(m64), uint8(s64), nil
}
// We expect as well a 6-character long value
if str := data.OpeningTime; len(str) == 6 {
t := &l.OpeningTime
var err error
t.Hours, t.Minutes, t.Seconds, err = parseTime(str)
if err != nil {
return gen.err(err, "OpeningTime", "opening_time", str, "error in parseTime")
}
}
if str := data.ClosingTime; len(str) == 6 {
t := &l.ClosingTime
var err error
t.Hours, t.Minutes, t.Seconds, err = parseTime(str)
if err != nil {
return gen.err(err, "ClosingTime", "closing_time", str, "error in parseTime")
}
}
return nil
}

44
types/line_test.go Normal file
View File

@ -0,0 +1,44 @@
package types
import (
"reflect"
"testing"
)
// Test_Line_Unmarshal tests unmarshalling for Line.
// As the unmarshalling is done in-house, this allows us to check that the custom UnmarshalJSON function correctly
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func Test_Line_Unmarshal(t *testing.T) {
testUnmarshal(t, testData["line"], reflect.TypeOf(Line{}))
}
// BenchmarkLineUnmarshal benchmarks Line unmarshalling via subbenchmarks
func BenchmarkLineUnmarshal(b *testing.B) {
// Get the bench data
data := testData["line"].bench
if len(data) == 0 {
b.Skip("No data to test")
}
// Run function generator, allowing parallel run
runGen := func(in []byte) func(*testing.B) {
return func(b *testing.B) {
for i := 0; i < b.N; i++ {
l := &Line{}
_ = l.UnmarshalJSON(in)
}
}
}
// Loop over all corpus
for name, datum := range data {
// Get run function
runFunc := runGen(datum)
// Run it !
b.Run(name, runFunc)
}
}

11
types/linereport.go Normal file
View File

@ -0,0 +1,11 @@
package types
type LineReports struct {
Disruptions []Disruption `json:"disruptions"`
LineReports []LineReport `json:"line_reports"`
}
type LineReport struct {
Line Line `json:"line"`
PTObjects []PTObject `json:"pt_objects"`
}

8
types/link.go Normal file
View File

@ -0,0 +1,8 @@
package types
type Link struct {
Href string `json:"href"`
Type string `json:"type"`
Rel string `json:"rel"`
Templated bool `json:"templated"`
}

7
types/message.go Normal file
View File

@ -0,0 +1,7 @@
package types
// A Message contains the text to be provided to the traveler.
type Message struct {
Text string `json:"text"` // The message to bring to the traveler
Channel *Channel `json:"channel"` // The destination media for this Message.
}

70
types/misc.go Normal file
View File

@ -0,0 +1,70 @@
package types
import (
"image/color"
"strconv"
"time"
"github.com/pkg/errors"
)
// DataFreshness codes for a specific data freshness requirement: realtime or base_schedule
type DataFreshness string
// parseColor, given a hex code #RRGGBB returns a color.NRGBA
func parseColor(str string) (color.NRGBA, error) {
var clr color.NRGBA
if len(str) != 6 {
return clr, errors.Errorf("parseColor: can't parse, invalid length (len=%d instead of 6)", len(str))
}
r, err := strconv.ParseUint(str[:2], 16, 8)
if err != nil {
return clr, errors.Wrapf(err, "parseColor: red component parsing failed (str: %s)", str[:2])
}
g, err := strconv.ParseUint(str[2:4], 16, 8)
if err != nil {
return clr, errors.Wrapf(err, "parseColor: green component parsing failed (str: %s)", str[2:4])
}
b, err := strconv.ParseUint(str[4:], 16, 8)
if err != nil {
return clr, errors.Wrapf(err, "parseColor: blue component parsing failed (str: %s)", str[4:])
}
return color.NRGBA{
R: uint8(r),
G: uint8(g),
B: uint8(b),
}, nil
}
const (
// DataFreshnessRealTime means you'll get undisrupted journeys
DataFreshnessRealTime DataFreshness = "realtime"
// DataFreshnessBaseSchedule means you can get disrupted journeys in the response.
DataFreshnessBaseSchedule = "base_schedule"
)
// A PTDateTime (pt stands for “public transport”) is a complex date time object to manage the difference between stop and leaving times at a stop.
// It is used by:
// - Row in Schedule
// - StopSchedule
// - StopDatetime
type PTDateTime struct {
// Date/Time of departure
Departure time.Time `json:"departure"`
// Date/Time of arrival
Arrival time.Time `json:"arrival"`
}
// A Code is associated to a dataset
//
// Every object managed by Navitia comes with its own list of ids.
// You will find some source ids, merge ids, etc. in “codes” list in json responses.
// Be careful, these codes may not be unique. The navitia id is the only unique id.
type Code struct {
Type string `json:"type"`
Value string `json:"value"`
}

66
types/mode.go Normal file
View File

@ -0,0 +1,66 @@
package types
// ModeXXX are known non-public transportation mode
const (
ModeWalking = "walking"
ModeBike = "bike"
ModeCar = "car"
// Not used in Section
ModeBikeShare = "bss"
)
// A CommercialMode codes for a commercial method of transportation.
//
// Note that in contrast with physical modes, commercial modes aren't normalised, if you want to query with them, it is best to use a PhysicalMode.
//
// See http://doc.navitia.io/#public-transport-objects
type CommercialMode struct {
// A CommercialMode ID is in the form of "commercial_mode:something"
ID ID `json:"id"`
// Name of the commercial mode
Name string `json:"name"`
// Physical modes of this commercial modes
// Example: []PhysicalMode{PhysicalMode{ID: "physical_mode:Tramway", Name: "Tramway"}}
PhysicalModes []PhysicalMode `json:"physical_modes"`
}
// A PhysicalMode codes for a physical method of transportation
// For example, air travel, bus, metro and train.
//
// As well, note that physical modes are normalised and fastened, see the list in PhysicalModes
//
// See http://doc.navitia.io/#public-transport-objects
type PhysicalMode struct {
// Identifier of the physical mode
// For example: "physical_mode:Tramway"
ID ID `json:"id"`
// Name of the physical mode
// For example: "Tramway"
Name string `json:"name"`
// Commercial modes of this physical mode
CommercialModes []CommercialMode `json:"commercial_mode"`
}
// PhysicalModeXXX are the possible physical modes in ID form
const (
PhysicalModeAir ID = "physical_mode:Air"
PhysicalModeBoat ID = "physical_mode:Boat"
PhysicalModeBus ID = "physical_mode:Bus"
PhysicalModeBusRapidTransit ID = "physical_mode:BusRapidTransit"
PhysicalModeCoach ID = "physical_mode:Coach"
PhysicalModeFerry ID = "physical_mode:Ferry"
PhysicalModeFunicular ID = "physical_mode:Funicular"
PhysicalModeLocalTrain ID = "physical_mode:LocalTrain"
PhysicalModeLongDistanceTrain ID = "physical_mode:LongDistanceTrain"
PhysicalModeMetro ID = "physical_mode:Metro"
PhysicalModeRapidTransit ID = "physical_mode:RapidTransit"
PhysicalModeShuttle ID = "physical_mode:Shuttle"
PhysicalModeTaxi ID = "physical_mode:Taxi"
PhysicalModeTrain ID = "physical_mode:Train"
PhysicalModeTramway ID = "physical_mode:Tramway"
)

9
types/network.go Normal file
View File

@ -0,0 +1,9 @@
package types
// Network represents a specific network.
// They are fed by the agencies in GTFS format.
// See http://doc.navitia.io/#public-transport-objects.
type Network struct {
ID string `json:"id"` // ID is the identifier of the network
Name string `json:"name"` // Name is the name of the network
}

54
types/pathSegment.go Normal file
View File

@ -0,0 +1,54 @@
package types
import (
"encoding/json"
"fmt"
"time"
)
// A PathSegment (called Path item in the Navitia API) is a part of a path
type PathSegment struct {
Length uint `json:"length"` // The Length of the segment
Name string `json:"name"` // The Name of the way corresponding to the segment
Duration time.Duration `json:"duration"` // The duration in seconds of the segment
// The angle in degree between the previous segment and this segment
// = 0 Means going straight
// < 0 Means turning left
// > 0 Means turning right
Direction int `json:"direction"`
}
// jsonPathSegment define the JSON implementation of PathSegment types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonPathSegment struct {
// Pointers to the corresponding real values
Length *uint
Name *string
Direction *int
// Value to process
Duration int64
}
// UnmarshalJSON implements json.Unmarshaller for a PathSegment
func (ps *PathSegment) UnmarshalJSON(b []byte) error {
data := &jsonPathSegment{
Length: &ps.Length,
Name: &ps.Name,
Direction: &ps.Direction,
}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling PathSegment: %w", err)
}
// Now process the value
// As the given duration is in second, let's multiply it by one second to have the correct value
ps.Duration = time.Duration(data.Duration) * time.Second
return nil
}

47
types/period.go Normal file
View File

@ -0,0 +1,47 @@
package types
import (
"encoding/json"
"time"
"github.com/pkg/errors"
)
// Period of effect
type Period struct {
Begin time.Time `json:"begin"`
End time.Time `json:"end"`
}
// UnmarshalJSON implements json.Unmarshaller for a Period
func (p *Period) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
// We define some of the value as pointers to the real values, allowing us to bypass copying in cases where we don't need to process the data
data := &struct {
// Those we will process
Begin string `json:"begin"`
End string `json:"end"`
}{}
// Let's create the error generator
gen := unmarshalErrorMaker{"Period", b}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return errors.Wrap(err, "Error while unmarshalling Period")
}
// Now we process the times.
p.Begin, err = parseDateTime(data.Begin)
if err != nil {
return gen.err(err, "Begin", "begin", data.Begin, "parseDateTime failed")
}
p.End, err = parseDateTime(data.End)
if err != nil {
return gen.err(err, "End", "end", data.End, "parseDateTime failed")
}
// Finished !
return nil
}

128
types/place.go Normal file
View File

@ -0,0 +1,128 @@
package types
// A Place isn't something directly used by the Navitia.io api.
//
// However, it allows the library user to use idiomatic go when working with the library.
// If you want a countainer, see Container
//
// Place is held by these types:
// - StopArea
// - POI
// - Address
// - StopPoint
// - Admin
type Place interface{}
// A StopArea represents a stop area: a nameable zone, where there are some stop points.
type StopArea struct {
ID ID `json:"id"`
Name string `json:"name"`
// Label of the stop area.
// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
// If you don't know what to display, display the label
Label string `json:"label"`
// Coordinates of the stop area
Coord Coordinates `json:"coord"`
// Administrative regions of the stop area in which is placed the stop area
Admins []Admin `json:"administrative_regions"`
// Stop points countained in this stop area
StopPoints []StopPoint `json:"stop_points"`
Timezone string `json:"timezone"`
}
// A POIType codes for the type of the point of interest
type POIType struct {
ID ID `json:"id"`
Name string `json:"name"`
}
// A POI is a Point Of Interest. A loosely-defined place.
type POI struct {
ID ID `json:"id"`
Name string `json:"name"`
// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
// If you don't know what to display, display the label
Label string `json:"label"`
// The type of the POI
Type POIType `json:"poi_type"`
}
// An Address codes for a real-world address: a point located in a street.
type Address struct {
ID ID `json:"id"`
Name string `json:"name"`
// Label of the address
// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
// If you don't know what to display, display the label
Label string `json:"label"`
// Coordinates of the address
Coord Coordinates `json:"coord"`
// House number of the address
HouseNumber uint `json:"house_number"`
// Administrative regions of the stop area in which is placed the stop area
Admins []Admin `json:"administrative_regions"`
}
// A StopPoint codes for a stop point in a line: a location where vehicles can pickup or drop off passengers.
type StopPoint struct {
ID ID `json:"id"`
// Name of the stop point
Name string `json:"name"`
Label string `json:"label"`
// Coordinates of the stop point
Coord Coordinates `json:"coord"`
// Administrative regions of the stop point
Admins []Admin `json:"administrative_regions"`
// List of equipments of the stop point
Equipments []Equipment `json:"equipment"`
// Stop Area countaining the stop point
StopArea *StopArea `json:"stop_area"`
CommercialModes []CommercialMode `json:"commercial_modes"`
Links []Link `json:"links"`
PhysicalModes []PhysicalMode `json:"physical_modes"`
FareZone FareZone `json:"fare_zone"`
}
// An Admin represents an administrative region: a region under the control/responsibility of a specific organisation.
// It can be a city, a district, a neightborhood, etc.
type Admin struct {
ID ID `json:"id"`
Name string `json:"name"`
// Label of the address
// The name is directly taken from the data whereas the label is something computed by navitia for better traveler information.
// If you don't know what to display, display the label
Label string `json:"label"`
// Coordinates of the administrative region
Coord Coordinates `json:"coord"`
// Level of the administrative region
Level int `json:"level"`
// Zip code of the administrative region
ZipCode string `json:"zip_code"`
Insee string `json:"insee"`
}

12
types/ptobject.go Normal file
View File

@ -0,0 +1,12 @@
package types
// A PTObject is a Public Transport object: StopArea, Trip, Line, Route, Network, etc.
type PTObject interface{}
// A Trip corresponds to a scheduled vehicle circulation (and all its linked real-time and disrupted routes).
//
// An example : a train, routing a Paris to Lyon itinerary every day at 06h29, is the “Trip” named “6641”.
type Trip struct {
ID ID `json:"id"`
Name string `json:"name"`
}

149
types/region.go Normal file
View File

@ -0,0 +1,149 @@
package types
import (
"encoding/json"
"fmt"
"time"
"github.com/mb0/wkt"
"github.com/pkg/errors"
"github.com/twpayne/go-geom"
)
// A Region holds information about a geographical region, including its ID, name & shape.
type Region struct {
ID ID `json:"id"` // Identifier of the region
Name string `json:"name"` // Name of the region
Status string `json:"status"` // Status of the dataset
// Shape of the region.
// You can use it to check if a particular coordinate is within that MultiPolygon
Shape *geom.MultiPolygon `json:"shape"`
DatasetCreation time.Time `json:"dataset_creation"` // When was the DataSet created ?
LastLoaded time.Time `json:"last_loaded"` // When was it last loaded at navitia.io's end ?
ProductionStart time.Time `json:"production_start"` // When did production start ?
ProductionEnd time.Time `json:"production_end"` // When did or when will it stop ?
// An error in the dataset.
// This comes from the server, not from this package.
Error string `json:"error"`
}
// jsonRegion define the JSON implementation of Region types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonRegion struct {
ID *ID `json:"id"`
Name *string `json:"name"`
Status *string `json:"status"`
// This is mind-fuckery of the highest level.
// While EVERY other geojson value returned by navitia is in standard format, THIS ONE, for NO GOOD REASON is coded in wkt...
// See (http://en.wikipedia.org/wiki/Well-known_text).
Shape string `json:"shape"`
DatasetCreation string `json:"dataset_created_at"`
LastLoaded string `json:"last_load_at"`
ProductionStart string `json:"start_production_date"`
ProductionEnd string `json:"end_production_date"`
Error *string `json:"error"`
}
// UnmarshalJSON implements json.Unmarshaller for a Region
func (r *Region) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
data := &jsonRegion{
ID: &r.ID,
Name: &r.Name,
Status: &r.Status,
Error: &r.Error,
}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling Region: %w", err)
}
// Let's create the error generator
gen := unmarshalErrorMaker{"Region", b}
// Now let's process the values
// First the times
r.DatasetCreation, err = parseDateTime(data.DatasetCreation)
if err != nil {
return gen.err(err, "DatasetCreation", "dataset_created_at", data.DatasetCreation, "Error while parsing datetime")
}
r.LastLoaded, err = parseDateTime(data.LastLoaded)
if err != nil {
return gen.err(err, "LastLoaded", "last_load_at", data.LastLoaded, "Error while parsing datetime")
}
r.ProductionStart, err = parseDateTime(data.ProductionStart)
if err != nil {
return gen.err(err, "ProductionStart", "start_production_date", data.ProductionStart, "Error while parsing datetime")
}
r.ProductionEnd, err = parseDateTime(data.ProductionEnd)
if err != nil {
return gen.err(err, "ProductionEnd", "end_production_date", data.ProductionEnd, "Error while parsing datetime")
}
// And now let's have some FUN, deal with the "shape" key.
// First, let's check if the string isn't empty, cause that would be so awesome...
if data.Shape != "" {
// Parse the MKT
out, err := wkt.Parse([]byte(data.Shape))
if err != nil {
return gen.err(err, "Shape", "shape", out, "error in wkt.Parse")
}
// Now, out should be a wkt.MultiPolygon
wktmp, ok := out.(*wkt.MultiPolygon)
if !ok {
return gen.err(nil, "Shape", "shape", out, "expected out to be of type wkt.MultiPolygon, but it isn't !")
}
// Call our funny little function to convert that to a geom format
mp, err := convertWktMPtoGeomMP(wktmp)
if err != nil {
return gen.err(err, "Shape", "shape", wktmp, "error while converting *wkt.MultiPolygon to *geom.MultiPolygon via convertWktMPtoGeomMP")
}
r.Shape = mp
}
return nil
}
// convertWktMPtoGeomMP converts a wkt MultiPolygon to a geom MultiPolygon
func convertWktMPtoGeomMP(in *wkt.MultiPolygon) (*geom.MultiPolygon, error) {
// Now let's convert it to a geom format
// First let's create the geom.MultiPolygon
mp := geom.NewMultiPolygon(geom.XY)
// Then let's iterate through the polygons, and convert each of them from wkt.Coord to geom.Coord
multipolygonCoords := make([][][]geom.Coord, len(in.Polygons))
for i, k := range in.Polygons {
polygonCoords := make([][]geom.Coord, len(k))
for j, l := range k {
coords := make([]geom.Coord, len(l))
for n, m := range l {
coord := make(geom.Coord, 2)
coord[0] = m.X
coord[1] = m.Y
coords[n] = coord
}
polygonCoords[j] = coords
}
multipolygonCoords[i] = polygonCoords
}
// Now assign it !
mp, err := mp.SetCoords(multipolygonCoords)
if err != nil {
return mp, errors.Wrapf(err, "Error while setting coordinates")
}
return mp, err
}

15
types/region_fuzz.go Normal file
View File

@ -0,0 +1,15 @@
// +build gofuzz
package types
func FuzzRegion(data []byte) int {
r := &Region{}
// Let's unmarshal
err := r.UnmarshalJSON(data)
if err != nil {
return 0
}
return 1
}

71
types/region_test.go Normal file
View File

@ -0,0 +1,71 @@
package types
import (
"fmt"
"reflect"
"strings"
"testing"
)
// Test_Region_Unmarshal tests unmarshalling for Region.
// As the unmarshalling is done in-house, this allows us to check that the custom UnmarshalJSON function correctly
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func Test_Region_Unmarshal(t *testing.T) {
testUnmarshal(t, testData["region"], reflect.TypeOf(Region{}))
}
// TestRegionUnmarshal_ShapeInvalidMKT tests known invalid MKT (well-known text) -encoded Region.Shape inputs for (*Region).UnmarshalJSON
func TestRegionUnmarshal_ShapeInvalidMKT(t *testing.T) {
// Shapes
shapes := [...]string{
"MULTIPOLYGON(((-11.33535 51.29165,0,0,-11.33535 51.29165))",
"MULTIPOLYGON((",
"MULTIPOLYGON(((-11.33535 51.29165,0,0,-11.33535 51.29165)",
"MULTIPOLYGON(",
"POLYGON(",
"MULTIPOLYGON(((0",
}
// Run
for i, s := range shapes {
in := []byte(fmt.Sprintf(`{"shape": "%s"}`, s))
r := &Region{}
err := r.UnmarshalJSON(in)
if err == nil {
t.Errorf("No error in run #%d even though we expected one", i)
} else if !strings.Contains(err.Error(), "EOF") {
t.Errorf("Unexpected error in run #%d with [%s]: %v", i, in, err)
}
}
}
// BenchmarkRegionUnmarshal benchmarks Region unmarshalling via subbenchmarks
func BenchmarkRegionUnmarshal(b *testing.B) {
// Get the bench data
data := testData["region"].bench
if len(data) == 0 {
b.Skip("No data to test")
}
// Run function generator, allowing parallel run
runGen := func(in []byte) func(*testing.B) {
return func(b *testing.B) {
for i := 0; i < b.N; i++ {
r := &Region{}
_ = r.UnmarshalJSON(in)
}
}
}
// Loop over all corpus
for name, datum := range data {
// Get run function
runFunc := runGen(datum)
// Run it !
b.Run(name, runFunc)
}
}

67
types/route.go Normal file
View File

@ -0,0 +1,67 @@
package types
import (
"encoding/json"
"fmt"
)
// A Route represents a route: a Line can have several routes,
// that is several directions with potential junctions and different frequency for each.
// See http://doc.navitia.io/#public-transport-objects.
type Route struct {
ID ID `json:"id"` // Identifier of the route, eg: "route:RAT:M6"
Name string `json:"name"` // Name of the route
Frequence bool `json:"is_frequence"` // If the route has frequency or not. Can only be “False”, but may be “True” in the future
Line Line `json:"line"` // Line is the line it is connected to
Direction Container `json:"direction"` // Direction is the direction of the route (Place or POI)
PhysicalModes []PhysicalMode `json:"physical_modes"` // PhysicalModes of the line
GeoJSON GeoJSON `json:"geo_json"`
}
// jsonRoute define the JSON implementation of Route types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonRoute struct {
ID *ID `json:"id"`
Name *string `json:"name"`
Line *Line `json:"line"`
Direction *Container `json:"direction"`
// Value to process
Frequence string `json:"is_frequence"`
}
type GeoJSON struct {
Type string `json:"type"`
}
// UnmarshalJSON implements json.Unmarshaller for Route
func (r *Route) UnmarshalJSON(b []byte) error {
data := &jsonRoute{
ID: &r.ID,
Name: &r.Name,
Line: &r.Line,
Direction: &r.Direction,
}
// Create the error generator
gen := unmarshalErrorMaker{"Route", b}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling Line")
}
// Now process the value
switch {
case data.Frequence == "true" || data.Frequence == "True":
r.Frequence = true
case data.Frequence == "false" || data.Frequence == "False":
r.Frequence = false
default:
return gen.err(nil, "Frequence", "is_frequency", data.Frequence, `String is neither True, true, False or false`)
}
return nil
}

16
types/route_test.go Normal file
View File

@ -0,0 +1,16 @@
package types
import (
"reflect"
"testing"
)
// Test_Route_Unmarshal tests unmarshalling for Route.
// As the unmarshalling is done in-house, this allows us to check that the custom UnmarshalJSON function correctly
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func Test_Route_Unmarshal(t *testing.T) {
testUnmarshal(t, testData["route"], reflect.TypeOf(Route{}))
}

235
types/section.go Normal file
View File

@ -0,0 +1,235 @@
package types
import (
"encoding/json"
"fmt"
"time"
"github.com/twpayne/go-geom"
"github.com/twpayne/go-geom/encoding/geojson"
)
// A Section holds information about a specific section
type Section struct {
Type SectionType
ID ID
Mode string
From Container
To Container
Departure time.Time // Departure time
Arrival time.Time // Arrival time
Duration time.Duration // Duration of travel
Path []PathSegment // The path taken by this section
Geo *geom.LineString // The path in geojson format
StopTimes []StopTime // List of the stop times of this section
Display Display // Information to display
Additional []PTMethod // Additional informations, from what I can see this is always a PTMethod
}
// jsonSection define the JSON implementation of Section types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonSection struct {
// Pointers to the corresponding real values
Type *SectionType `json:"type"`
ID *ID `json:"id"`
From *Container `json:"from"`
To *Container `json:"to"`
Mode *string `json:"mode"`
StopTimes *[]StopTime `json:"stop_date_times"`
Display *Display `json:"display_informations"`
Additional *[]PTMethod `json:"additional_informations"`
Path *[]PathSegment `json:"path"`
// Values to process
Departure string `json:"departure_date_time"`
Arrival string `json:"arrival_date_time"`
Duration int64 `json:"duration"`
Geo *geojson.Geometry `json:"geojson"`
}
// A SectionType codifies the type of section that can be encountered
type SectionType string
// These are the types of sections that can be returned from the API
const (
// Public transport section
SectionPublicTransport SectionType = "public_transport"
// Street section
SectionStreetNetwork SectionType = "street_network"
// Waiting section between transport
SectionWaiting SectionType = "waiting"
// This “stay in the vehicle” section occurs when the traveller has to stay in the vehicle when the bus change its routing.
SectionStayIn SectionType = "stay_in"
// Transfer section
SectionTransfer SectionType = "transfer"
// Teleportation section. Used when starting or arriving to a city or a stoparea (“potato shaped” objects) Useful to make navitia idempotent.
// Warning: Be careful: no Path nor Geo items in this case
SectionCrowFly SectionType = "crow_fly"
// Vehicle may not drive along: traveler will have to call agency to confirm journey
// Also sometimes called ODT
SectionOnDemandTransport SectionType = "on_demand_transport"
// Taking a bike from a bike sharing system (bss)
SectionBikeShareRent SectionType = "bss_rent"
// Putting back a bike from a bike sharing system (bss)
SectionBikeSharePutBack SectionType = "bss_put_back"
// Boarding on plane
SectionBoarding SectionType = "boarding"
// Landing off the plane
SectionLanding SectionType = "landing"
)
// SectionTypes is the type of a section
var SectionTypes = map[SectionType]string{
SectionPublicTransport: "Public transport section",
SectionStreetNetwork: "Street section",
SectionWaiting: "Waiting section between transport",
SectionStayIn: "This “stay in the vehicle” section occurs when the traveller has to stay in the vehicle when the bus change its routing.",
SectionTransfer: "Transfer section",
SectionCrowFly: "Teleportation section. Used when starting or arriving to a city or a stoparea (“potato shaped” objects) Useful to make navitia idempotent",
SectionOnDemandTransport: "Vehicle may not drive along: traveler will have to call agency to confirm journey",
SectionBikeShareRent: "Taking a bike from a bike sharing system (bss)",
SectionBikeSharePutBack: "Putting back a bike from a bike sharing system (bss)",
SectionBoarding: "Boarding on plane",
SectionLanding: "Landing off the plane",
}
// A StopTime stores info about a stop in a route: when the vehicle comes in, when it comes out, and what stop it is.
type StopTime struct {
// The PTDateTime of the stop, this stores the info about the arrival & departure
PTDateTime PTDateTime
StopPoint StopPoint `json:"stop_point"` // The stop point in question
DropOffAllowed bool `json:"drop_off_allowed"`
UTCDepartureTime string `json:"utc_departure_time"`
Headsign string `json:"headsign"`
UTCArrivalTime string `json:"utc_arrival_time"`
PickupAllowed bool `json:"pickup_allowed"`
DepartureTime string `json:"departure_time"`
}
// A PTMethod is a Public Transportation method: it can be regular, estimated times or ODT (on-demand transport)
type PTMethod string
// PTMethodXXX codes for known PTMethod
const (
// PTMethodRegular: No on-demand transport. Line does not contain any estimated stop times, nor zonal stop point location. No need to call too.
PTMethodRegular PTMethod = "regular"
// PTMethodDateTimeEstimated: No on-demand transport. However, line has at least one estimated date time.
PTMethodDateTimeEstimated PTMethod = "had_date_time_estimated"
// PTMethodODTStopTime: Line does not contain any estimated stop times, nor zonal stop point location. But you will have to call to take it.
PTMethodODTStopTime PTMethod = "odt_with_stop_time"
// PTMethodODTStopPoint: Line can contain some estimated stop times, but no zonal stop point location. And you will have to call to take it.
PTMethodODTStopPoint PTMethod = "odt_with_stop_point"
// PTMethodODTZone: Line can contain some estimated stop times, and zonal stop point location. And you will have to call to take it. Well, not really a public transport line, more a cab…
PTMethodODTZone PTMethod = "odt_with_zone"
)
/*
UnmarshalJSON implements json.Unmarshaller for a Section
Behaviour:
- If "from" is empty, then don't populate the From field.
- Same for "to"
*/
func (s *Section) UnmarshalJSON(b []byte) error {
data := &jsonSection{
Type: &s.Type,
ID: &s.ID,
From: &s.From,
To: &s.To,
Mode: &s.Mode,
Display: &s.Display,
Additional: &s.Additional,
StopTimes: &s.StopTimes,
Path: &s.Path,
}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling Section: %w", err)
}
// Create the error generator
gen := unmarshalErrorMaker{"Section", b}
// For departure and arrival, we use parseDateTime
s.Departure, err = parseDateTime(data.Departure)
if err != nil {
return gen.err(err, "Departure", "departure_date_time", data.Departure, "parseDateTime failed")
}
s.Arrival, err = parseDateTime(data.Arrival)
if err != nil {
return gen.err(err, "Arrival", "arrival_date_time", data.Arrival, "parseDateTime failed")
}
// As the given duration is in second, let's multiply it by one second to have the correct value
s.Duration = time.Duration(data.Duration) * time.Second
// Now let's deal with the geom
if data.Geo != nil {
// Catch an error !
if data.Geo.Coordinates == nil {
return gen.err(nil, "Geo", "geojson", data.Geo, "Geo.Coordinates is nil, can't continue as that will cause a panic")
}
// Let's decode it
geot, err := data.Geo.Decode()
if err != nil {
return gen.err(err, "Geo", "geojson", data.Geo, "Geo.Decode() failed")
}
// And let's assert the type
geo, ok := geot.(*geom.LineString)
if !ok {
return gen.err(err, "Geo", "geojson", data.Geo, "Geo type assertion failed!")
}
// Now let's assign it
s.Geo = geo
}
return nil
}
// UnmarshalJSON implements json.Unmarshaller for a PTDateTime
func (ptdt *PTDateTime) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
data := &struct {
Departure string `json:"departure_date_time"`
Arrival string `json:"arrival_date_time"`
}{}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling PTDateTime: %w", err)
}
// Create the error generator
gen := unmarshalErrorMaker{"PTDateTime", b}
// Now we use parseDateTime
ptdt.Departure, err = parseDateTime(data.Departure)
if err != nil {
return gen.err(err, "Departure", "departure_date_time", data.Departure, "parseDateTime failed")
}
ptdt.Arrival, err = parseDateTime(data.Arrival)
if err != nil {
return gen.err(err, "Arrival", "arrival_date_time", data.Arrival, "parseDateTime failed")
}
return nil
}

16
types/section_test.go Normal file
View File

@ -0,0 +1,16 @@
package types
import (
"reflect"
"testing"
)
// Test_Section_Unmarshal tests unmarshalling for Section.
// As the unmarshalling is done in-house, this allows us to check that the custom UnmarshalJSON function correctly
//
// This launches both a "correct" and "incorrect" subtest, allowing us to test both cases.
// If we expect no errors but we get one, the test fails
// If we expect an error but we don't get one, the test fails
func Test_Section_Unmarshal(t *testing.T) {
testUnmarshal(t, testData["section"], reflect.TypeOf(Section{}))
}

66
types/severity.go Normal file
View File

@ -0,0 +1,66 @@
package types
import (
"encoding/json"
"fmt"
"image/color"
)
// Severity object can be used to make visual grouping.
type Severity struct {
// Name of severity
Name string `json:"name"`
// Priority of the severity. Given by the agency. 0 is the strongest priority, a nil Priority means its undefined (duh).
Priority *int `json:"priority"`
// HTML color for classification
Color color.Color `json:"color"`
// Effect: Normalized value of the effect on the public transport object
Effect Effect `json:"effect"`
}
// jsonSeverity define the JSON implementation of Severity types
// We define some of the value as pointers to the real values,
// allowing us to bypass copying in cases where we don't need to process the data.
type jsonSeverity struct {
// The references
Name *string `json:"name"`
Priority *int `json:"priority,omitempty"` // As priority can be null, and 0 is the highest priority.
Effect *Effect `json:"effect"`
// Those we will process
Color string `json:"color"`
}
// UnmarshalJSON implements json.Unmarshaller for a Severity
func (s *Severity) UnmarshalJSON(b []byte) error {
// First let's create the analogous structure
// We define some of the value as pointers to the real values, allowing us to bypass copying in cases where we don't need to process the data
data := &jsonSeverity{
Name: &s.Name,
Priority: s.Priority,
Effect: &s.Effect,
}
// Let's create the error generator
gen := unmarshalErrorMaker{"Severity", b}
// Now unmarshall the raw data into the analogous structure
err := json.Unmarshal(b, data)
if err != nil {
return fmt.Errorf("error while unmarshalling Severity: %w", err)
}
// Process the color
if str := data.Color; len(str) == 6 {
clr, err := parseColor(str)
if err != nil {
return gen.err(err, "Color", "color", str, "error in parseColor")
}
s.Color = clr
}
return nil
}

View File

@ -0,0 +1,41 @@
{
"embedded_type": "stop_area",
"quality": 70,
"stop_area": {
"codes": [
{
"type": "external_code",
"value": "RATRDBAC"
},
{
"type": "source",
"value": "RDBAC"
}
],
"name": "Rue du Bac",
"links": [],
"coord": {
"lat": "48.855756",
"lon": "2.325569"
},
"label": "Rue du Bac (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"timezone": "Europe\/Paris",
"id": "stop_area:RAT:SA:RDBAC"
},
"name": "Rue du Bac (Paris)",
"id": "stop_area:RAT:SA:RDBAC"
}

View File

@ -0,0 +1,41 @@
{
"embedded_type": "stop_area",
"quality": 70,
"stop_area": {
"codes": [
{
"type": "external_code",
"value": "RATRDBAC"
},
{
"type": "source",
"value": "RDBAC"
}
],
"name": "Rue du Bac",
"links": [],
"coord": {
"lat": "48.855756",
"lon": "2.325569"
},
"label": "Rue du Bac (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"timezone": "Europe\/Paris",
"id": "stop_area:RAT:SA:RDBAC"
},
"name": "Rue du Bac (Paris)",
"id": "stop_area:RAT:SA:RDBAC"
}

View File

@ -0,0 +1,41 @@
{
"embedded_type": "stop_area",
"quality": 60,
"stop_area": {
"codes": [
{
"type": "external_code",
"value": "RATMKFDO"
},
{
"type": "source",
"value": "MKFDO"
}
],
"name": "Malakoff \u2014 Rue Etienne Dolet",
"links": [],
"coord": {
"lat": "48.814668",
"lon": "2.296999"
},
"label": "Malakoff \u2014 Rue Etienne Dolet (Malakoff)",
"administrative_regions": [
{
"insee": "92046",
"name": "Malakoff",
"level": 8,
"coord": {
"lat": "48.817406",
"lon": "2.297158"
},
"label": "Malakoff (92240)",
"id": "admin:fr:92046",
"zip_code": "92240"
}
],
"timezone": "Europe\/Paris",
"id": "stop_area:RAT:SA:MKFDO"
},
"name": "Malakoff \u2014 Rue Etienne Dolet (Malakoff)",
"id": "stop_area:RAT:SA:MKFDO"
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 80,
"id": "poi:n682262148",
"name": "Rue Chabanais (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Rue Chabanais",
"coord": {
"lat": "48.8669921",
"lon": "2.3366321"
},
"label": "Rue Chabanais (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 1,
"id": "2.3366321;48.8669921",
"name": "Rue Chabanais",
"coord": {
"lat": "48.8669921",
"lon": "2.3366321"
},
"label": "1 Rue Chabanais (Paris)"
},
"id": "poi:n682262148",
"properties": {
"amenity": "bicycle_rental",
"name": "Rue Chabanais",
"source": "cadastre-dgi-fr source : Direction G\u00e9n\u00e9rale des Imp\u00f4ts - Cadastre. Mise \u00e0 jour : 2010",
"operator": "JCDecaux",
"ref": "02007",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 80,
"id": "poi:n639606894",
"name": "Rue Moncey (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Rue Moncey",
"coord": {
"lat": "48.8801859",
"lon": "2.3312932"
},
"label": "Rue Moncey (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 2,
"id": "2.3312932;48.8801859",
"name": "Rue Moncey",
"coord": {
"lat": "48.8801859",
"lon": "2.3312932"
},
"label": "2 Rue Moncey (Paris)"
},
"id": "poi:n639606894",
"properties": {
"amenity": "bicycle_rental",
"capacity": "N\/A",
"name": "Rue Moncey",
"wheelchair": "no",
"operator": "JCDecaux",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 80,
"id": "poi:n597860967",
"name": "Rue montgallet (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Rue montgallet",
"coord": {
"lat": "48.844328",
"lon": "2.3896931"
},
"label": "Rue montgallet (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 39,
"id": "2.3896931;48.844328",
"name": "Rue Montgallet",
"coord": {
"lat": "48.844328",
"lon": "2.3896931"
},
"label": "39 Rue Montgallet (Paris)"
},
"id": "poi:n597860967",
"properties": {
"amenity": "bicycle_rental",
"capacity": "16",
"name": "Rue montgallet",
"operator": "JCDecaux",
"ref": "12013",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n439912307",
"name": "Hittorf - Rue Hittorf - 75010 Paris (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Hittorf - Rue Hittorf - 75010 Paris",
"coord": {
"lat": "48.8720809",
"lon": "2.3576446"
},
"label": "Hittorf - Rue Hittorf - 75010 Paris (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 14,
"id": "2.3576446;48.8720809",
"name": "Rue Hittorf",
"coord": {
"lat": "48.8720809",
"lon": "2.3576446"
},
"label": "14 Rue Hittorf (Paris)"
},
"id": "poi:n439912307",
"properties": {
"amenity": "bicycle_rental",
"capacity": "17",
"name": "Hittorf - Rue Hittorf - 75010 Paris",
"operator": "JCDecaux",
"ref": "10009",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,52 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n272853107",
"name": "Rue de Siam (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Rue de Siam",
"coord": {
"lat": "48.861679",
"lon": "2.2753896"
},
"label": "Rue de Siam (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 1,
"id": "2.2753896;48.861679",
"name": "Rue de Siam",
"coord": {
"lat": "48.861679",
"lon": "2.2753896"
},
"label": "1 Rue de Siam (Paris)"
},
"id": "poi:n272853107",
"properties": {
"amenity": "bicycle_rental",
"capacity": "16",
"name": "Rue de Siam",
"source": "survey",
"operator": "JCDecaux",
"ref": "16017",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n340402115",
"name": "Rue des Boulets (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Rue des Boulets",
"coord": {
"lat": "48.8521875",
"lon": "2.3889688"
},
"label": "Rue des Boulets (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 45,
"id": "2.3889688;48.8521875",
"name": "Rue des Boulets",
"coord": {
"lat": "48.8521875",
"lon": "2.3889688"
},
"label": "45 Rue des Boulets (Paris)"
},
"id": "poi:n340402115",
"properties": {
"amenity": "bicycle_rental",
"capacity": "23",
"name": "Rue des Boulets",
"operator": "JCDecaux",
"ref": "11009",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n272852792",
"name": "Rue Fran\u00e7ois Ponsard (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Rue Fran\u00e7ois Ponsard",
"coord": {
"lat": "48.8583046",
"lon": "2.2742742"
},
"label": "Rue Fran\u00e7ois Ponsard (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 4,
"id": "2.2742742;48.8583046",
"name": "Chauss\u00e9e de la Muette",
"coord": {
"lat": "48.8583046",
"lon": "2.2742742"
},
"label": "4 Chauss\u00e9e de la Muette (Paris)"
},
"id": "poi:n272852792",
"properties": {
"amenity": "bicycle_rental",
"capacity": "23",
"name": "Rue Fran\u00e7ois Ponsard",
"operator": "JCDecaux",
"ref": "16021",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 60,
"id": "poi:n439919694",
"name": "Beaubourg - 46 Rue Beaubourg - 75003 Paris (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Beaubourg - 46 Rue Beaubourg - 75003 Paris",
"coord": {
"lat": "48.8610006",
"lon": "2.353484"
},
"label": "Beaubourg - 46 Rue Beaubourg - 75003 Paris (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 26,
"id": "2.353484;48.8610006",
"name": "Rue Geoffroy l'Angevin",
"coord": {
"lat": "48.8610006",
"lon": "2.353484"
},
"label": "26 Rue Geoffroy l'Angevin (Paris)"
},
"id": "poi:n439919694",
"properties": {
"amenity": "bicycle_rental",
"capacity": "18",
"name": "Beaubourg - 46 Rue Beaubourg - 75003 Paris",
"operator": "JCDecaux",
"ref": "3010",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 80,
"id": "poi:n2025403733",
"name": "avenue Marceau (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "avenue Marceau",
"coord": {
"lat": "48.8652776",
"lon": "2.3001217"
},
"label": "avenue Marceau (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 4,
"id": "2.3001217;48.8652776",
"name": "Avenue Marceau",
"coord": {
"lat": "48.8652776",
"lon": "2.3001217"
},
"label": "4 Avenue Marceau (Paris)"
},
"id": "poi:n2025403733",
"properties": {
"amenity": "bicycle_rental",
"capacity": "30",
"name": "avenue Marceau",
"operator": "JCDecaux",
"ref": "8046",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n4037878821",
"name": "13, Avenue Foch (Paris)",
"poi": {
"poi_type": {
"name": "Parking v\u00e9lo",
"id": "poi_type:amenity:bicycle_parking"
},
"name": "13, Avenue Foch",
"coord": {
"lat": "48.845978",
"lon": "2.440875"
},
"label": "13, Avenue Foch (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 11,
"id": "2.440875;48.845978",
"name": "Avenue Foch",
"coord": {
"lat": "48.845978",
"lon": "2.440875"
},
"label": "11 Avenue Foch"
},
"id": "poi:n4037878821",
"properties": {
"amenity": "bicycle_parking",
"name": "13, Avenue Foch",
"access": "permissive",
"operator": "10",
"covered": "no",
"bicycle_parking": "rack"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n340398579",
"name": "Avenue de Gravelle (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Avenue de Gravelle",
"coord": {
"lat": "48.8243871",
"lon": "2.4184684"
},
"label": "Avenue de Gravelle (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 0,
"id": "2.4184684;48.8243871",
"name": "Rue du Bac",
"coord": {
"lat": "48.8243871",
"lon": "2.4184684"
},
"label": "Rue du Bac"
},
"id": "poi:n340398579",
"properties": {
"amenity": "bicycle_rental",
"capacity": "50",
"name": "Avenue de Gravelle",
"operator": "JCDecaux",
"ref": "12126",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,52 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n1490011488",
"name": "Avenue des Gobelins (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Avenue des Gobelins",
"coord": {
"lat": "48.8371959",
"lon": "2.3514837"
},
"label": "Avenue des Gobelins (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 22,
"id": "2.3514837;48.8371959",
"name": "Avenue des Gobelins",
"coord": {
"lat": "48.8371959",
"lon": "2.3514837"
},
"label": "22 Avenue des Gobelins (Paris)"
},
"id": "poi:n1490011488",
"properties": {
"amenity": "bicycle_rental",
"capacity": "40",
"name": "Avenue des Gobelins",
"wheelchair": "no",
"operator": "JCDecaux",
"ref": "0527",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n489537569",
"name": "Avenue des Portugais (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Avenue des Portugais",
"coord": {
"lat": "48.8711878",
"lon": "2.2937312"
},
"label": "Avenue des Portugais (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 0,
"id": "2.2937312;48.8711878",
"name": "Avenue des Portugais",
"coord": {
"lat": "48.8711878",
"lon": "2.2937312"
},
"label": "Avenue des Portugais (Paris)"
},
"id": "poi:n489537569",
"properties": {
"amenity": "bicycle_rental",
"capacity": "26",
"name": "Avenue des Portugais",
"operator": "JCDecaux",
"ref": "16001",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,50 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n1379439290",
"name": "Avenue des Ternes (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Avenue des Ternes",
"coord": {
"lat": "48.8794462",
"lon": "2.2915207"
},
"label": "Avenue des Ternes (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 2,
"id": "2.2915207;48.8794462",
"name": "Place Tristan Bernard",
"coord": {
"lat": "48.8794462",
"lon": "2.2915207"
},
"label": "2 Place Tristan Bernard (Paris)"
},
"id": "poi:n1379439290",
"properties": {
"operator": "JCDecaux",
"amenity": "bicycle_rental",
"ref": "17036",
"name": "Avenue des Ternes",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n272853313",
"name": "Avenue Henri Martin (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Avenue Henri Martin",
"coord": {
"lat": "48.864084",
"lon": "2.2768625"
},
"label": "Avenue Henri Martin (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 71,
"id": "2.2768625;48.864084",
"name": "Avenue Henri Martin",
"coord": {
"lat": "48.864084",
"lon": "2.2768625"
},
"label": "71 Avenue Henri Martin (Paris)"
},
"id": "poi:n272853313",
"properties": {
"amenity": "bicycle_rental",
"capacity": "34",
"name": "Avenue Henri Martin",
"operator": "JCDecaux",
"ref": "16013",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n1406238646",
"name": "Avenue Rene Coty (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Avenue Rene Coty",
"coord": {
"lat": "48.8248017",
"lon": "2.3362648"
},
"label": "Avenue Rene Coty (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 48,
"id": "2.3362648;48.8248017",
"name": "Avenue Reille",
"coord": {
"lat": "48.8248017",
"lon": "2.3362648"
},
"label": "48 Avenue Reille (Paris)"
},
"id": "poi:n1406238646",
"properties": {
"amenity": "bicycle_rental",
"name": "Avenue Rene Coty",
"wheelchair": "no",
"operator": "JCDecaux",
"ref": "14016",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 60,
"id": "poi:n2304319864",
"name": "10 Avenue des Minimes (Paris)",
"poi": {
"poi_type": {
"name": "Parking v\u00e9lo",
"id": "poi_type:amenity:bicycle_parking"
},
"name": "10 Avenue des Minimes",
"coord": {
"lat": "48.8411291",
"lon": "2.4320878"
},
"label": "10 Avenue des Minimes (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 0,
"id": "2.4320878;48.8411291",
"name": "Rue Louis Besquel",
"coord": {
"lat": "48.8411291",
"lon": "2.4320878"
},
"label": "Rue Louis Besquel"
},
"id": "poi:n2304319864",
"properties": {
"amenity": "bicycle_parking",
"capacity": "20",
"name": "10 Avenue des Minimes",
"supervised": "no",
"covered": "no",
"bicycle_parking": "stands"
}
}
}

View File

@ -0,0 +1,48 @@
{
"embedded_type": "poi",
"quality": 60,
"id": "poi:n4689211908",
"name": "32 Avenue Anatole France (Paris)",
"poi": {
"poi_type": {
"name": "Parking v\u00e9lo",
"id": "poi_type:amenity:bicycle_parking"
},
"name": "32 Avenue Anatole France",
"coord": {
"lat": "48.8420506",
"lon": "2.4316558"
},
"label": "32 Avenue Anatole France (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 47,
"id": "2.4316558;48.8420506",
"name": "Rue des Vignerons",
"coord": {
"lat": "48.8420506",
"lon": "2.4316558"
},
"label": "47 Rue des Vignerons"
},
"id": "poi:n4689211908",
"properties": {
"source": "Mairie de Vincennes",
"amenity": "bicycle_parking",
"name": "32 Avenue Anatole France"
}
}
}

View File

@ -0,0 +1,18 @@
{
"embedded_type": "administrative_region",
"quality": 70,
"administrative_region": {
"insee": "7511559",
"name": "Quartier de Grenelle",
"level": 10,
"coord": {
"lat": "48.850168",
"lon": "2.29184"
},
"label": "Quartier de Grenelle (75015)",
"id": "admin:fr:7511559",
"zip_code": "75015"
},
"id": "admin:fr:7511559",
"name": "Quartier de Grenelle (75015)"
}

View File

@ -0,0 +1,41 @@
{
"embedded_type": "stop_area",
"quality": 50,
"stop_area": {
"codes": [
{
"type": "external_code",
"value": "RATLMPGR"
},
{
"type": "source",
"value": "LMPGR"
}
],
"name": "La Motte-Picquet \u2014 Grenelle",
"links": [],
"coord": {
"lat": "48.84916",
"lon": "2.297949"
},
"label": "La Motte-Picquet \u2014 Grenelle (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"timezone": "Europe\/Paris",
"id": "stop_area:RAT:SA:LMPGR"
},
"name": "La Motte-Picquet \u2014 Grenelle (Paris)",
"id": "stop_area:RAT:SA:LMPGR"
}

View File

@ -0,0 +1,52 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:n305103675",
"name": "Grenelle Violet (prop3) (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Grenelle Violet (prop3)",
"coord": {
"lat": "48.8499385",
"lon": "2.2945842"
},
"label": "Grenelle Violet (prop3) (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 88,
"id": "2.2945842;48.8499385",
"name": "Boulevard de Grenelle",
"coord": {
"lat": "48.8499385",
"lon": "2.2945842"
},
"label": "88 Boulevard de Grenelle (Paris)"
},
"id": "poi:n305103675",
"properties": {
"amenity": "bicycle_rental",
"capacity": "53",
"name": "Grenelle Violet (prop3)",
"wheelchair": "no",
"operator": "JCDecaux",
"ref": "15106",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,50 @@
{
"embedded_type": "poi",
"quality": 70,
"id": "poi:w99577109",
"name": "Square des Gr\u00e8s (Paris)",
"poi": {
"poi_type": {
"name": "Parc, espace vert",
"id": "poi_type:leisure:park"
},
"name": "Square des Gr\u00e8s",
"coord": {
"lat": "48.85956934",
"lon": "2.406174677"
},
"label": "Square des Gr\u00e8s (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 14,
"id": "2.406174677;48.85956934",
"name": "Rue Riblette",
"coord": {
"lat": "48.85956934",
"lon": "2.406174677"
},
"label": "14 Rue Riblette (Paris)"
},
"id": "poi:w99577109",
"properties": {
"wikipedia": "fr:Square des Gr\u00e8s",
"wikidata": "Q3494997",
"name": "Square des Gr\u00e8s",
"leisure": "park",
"start_date": "1983"
}
}
}

View File

@ -0,0 +1,52 @@
{
"embedded_type": "poi",
"quality": 50,
"id": "poi:n672727214",
"name": "Commissariat de police Javel-Grenelle (Paris)",
"poi": {
"poi_type": {
"name": "Police, gendarmerie",
"id": "poi_type:amenity:police"
},
"name": "Commissariat de police Javel-Grenelle",
"coord": {
"lat": "48.8433337",
"lon": "2.2768334"
},
"label": "Commissariat de police Javel-Grenelle (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 34,
"id": "2.2768334;48.8433337",
"name": "Rue Balard",
"coord": {
"lat": "48.8433337",
"lon": "2.2768334"
},
"label": "34 Commissariat de police Javel-Grenelle (Paris)"
},
"id": "poi:n672727214",
"properties": {
"addr:housenumber": "34",
"amenity": "police",
"addr:city": "Paris",
"addr:postcode": "75015",
"name": "Commissariat de police Javel-Grenelle",
"addr:country": "FR",
"addr:street": "Rue Balard"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 50,
"id": "poi:n60751375",
"name": "Sebastopol Grenata - 12 Rue Grenata - 75002 Paris (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Sebastopol Grenata - 12 Rue Grenata - 75002 Paris",
"coord": {
"lat": "48.8652569",
"lon": "2.3516674"
},
"label": "Sebastopol Grenata - 12 Rue Grenata - 75002 Paris (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 12,
"id": "2.3516674;48.8652569",
"name": "Rue Greneta",
"coord": {
"lat": "48.8652569",
"lon": "2.3516674"
},
"label": "12 Rue Greneta (Paris)"
},
"id": "poi:n60751375",
"properties": {
"amenity": "bicycle_rental",
"capacity": "34",
"name": "Sebastopol Grenata - 12 Rue Grenata - 75002 Paris",
"operator": "JCDecaux",
"ref": "2001",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 40,
"id": "poi:n439924298",
"name": "Grenier Saint-Lazare - 34 Rue Grenier Saint-Lazare - 75003 Paris (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Grenier Saint-Lazare - 34 Rue Grenier Saint-Lazare - 75003 Paris",
"coord": {
"lat": "48.8631013",
"lon": "2.3527609"
},
"label": "Grenier Saint-Lazare - 34 Rue Grenier Saint-Lazare - 75003 Paris (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 34,
"id": "2.3527609;48.8631013",
"name": "Rue du Grenier Saint-Lazare",
"coord": {
"lat": "48.8631013",
"lon": "2.3527609"
},
"label": "34 Rue du Grenier Saint-Lazare (Paris)"
},
"id": "poi:n439924298",
"properties": {
"amenity": "bicycle_rental",
"capacity": "31",
"name": "Grenier Saint-Lazare - 34 Rue Grenier Saint-Lazare - 75003 Paris",
"operator": "JCDecaux",
"ref": "3014",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,51 @@
{
"embedded_type": "poi",
"quality": 40,
"id": "poi:n310350237",
"name": "Square Bela Bartok - Quai Grenelle - 75015 Paris (Paris)",
"poi": {
"poi_type": {
"name": "Station VLS",
"id": "poi_type:amenity:bicycle_rental"
},
"name": "Square Bela Bartok - Quai Grenelle - 75015 Paris",
"coord": {
"lat": "48.8511757",
"lon": "2.2845792"
},
"label": "Square Bela Bartok - Quai Grenelle - 75015 Paris (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"address": {
"house_number": 2,
"id": "2.2845792;48.8511757",
"name": "Place de Brazzaville",
"coord": {
"lat": "48.8511757",
"lon": "2.2845792"
},
"label": "2 Place de Brazzaville (Paris)"
},
"id": "poi:n310350237",
"properties": {
"amenity": "bicycle_rental",
"capacity": "23",
"name": "Square Bela Bartok - Quai Grenelle - 75015 Paris",
"operator": "JCDecaux",
"ref": "15102",
"network": "V\u00e9lib'"
}
}
}

View File

@ -0,0 +1,30 @@
{
"embedded_type": "address",
"quality": 80,
"id": "2.397900446545659;48.86088080214612",
"name": "Avenue Greffulhe (Paris)",
"address": {
"name": "Avenue Greffulhe",
"house_number": 0,
"coord": {
"lat": "48.8608808021",
"lon": "2.39790044655"
},
"label": "Avenue Greffulhe (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"id": "2.397900446545659;48.86088080214612"
}
}

View File

@ -0,0 +1,30 @@
{
"embedded_type": "address",
"quality": 80,
"id": "2.35;48.8652835",
"name": "Cour Greneta (Paris)",
"address": {
"name": "Cour Greneta",
"house_number": 0,
"coord": {
"lat": "48.8652835",
"lon": "2.35"
},
"label": "Cour Greneta (Paris)",
"administrative_regions": [
{
"insee": "75056",
"name": "Paris",
"level": 8,
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"label": "Paris",
"id": "admin:fr:75056",
"zip_code": ""
}
],
"id": "2.35;48.8652835"
}
}

View File

@ -0,0 +1,11 @@
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x4f1cdb]
goroutine 1 [running]:
github.com/aabizri/gonavitia/types.FuzzPlaceCountainer(0x7fa709ccf000, 0x2, 0x200000, 0x3)
/tmp/go-fuzz-build662575377/gopath/src/github.com/aabizri/gonavitia/types/place_fuzz.go:22 +0x18b
go-fuzz-dep.Main(0x53b308)
/tmp/go-fuzz-build662575377/goroot/src/go-fuzz-dep/main.go:49 +0xde
main.main()
/tmp/go-fuzz-build662575377/gopath/src/github.com/aabizri/gonavitia/types/go.fuzz.main/main.go:10 +0x2d
exit status 2

202
types/testdata/create.go vendored Normal file
View File

@ -0,0 +1,202 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
)
type journeyRequest struct {
Journeys []json.RawMessage `json:"journeys"`
}
func (r journeyRequest) messages() []json.RawMessage {
return r.Journeys
}
type placeRequest struct {
Places []json.RawMessage `json:"places"`
}
func (r placeRequest) messages() []json.RawMessage {
return r.Places
}
type coverageRequest struct {
Regions []json.RawMessage `json:"regions"`
}
func (r coverageRequest) messages() []json.RawMessage {
return r.Regions
}
type request interface {
messages() []json.RawMessage
}
var (
originFlag = flag.String("from", "../../testdata", "Original directory")
destinationFlag = flag.String("to", "./", "Destination directory")
originPath string
destinationPath string
)
var equivalence = map[string]string{
"journeys": "journey",
"places": "place",
"coverage": "region",
}
// load loads the origin directory and files
func load(path string) (map[string][]*os.File, error) {
subDirs, err := ioutil.ReadDir(path)
if err != nil {
fmt.Printf("Error while listing subdirs !: %v\n", err)
return nil, err
}
originFiles := make(map[string][]*os.File, len(subDirs))
for _, dinfo := range subDirs {
dirName := dinfo.Name()
if !dinfo.IsDir() {
fmt.Printf("Skipping %s...\n", dirName)
} else {
fmt.Printf("Processing %s directory...\n", dirName)
files, err := ioutil.ReadDir(filepath.Join(originPath, dirName))
if err != nil {
fmt.Printf("Error while reading %s directory !: %v\n", dirName, err)
return originFiles, err
}
for _, finfo := range files {
fmt.Printf("\tProcessing %s...\n", finfo.Name())
fname := finfo.Name()
if fname[len(fname)-4:] != "json" {
fmt.Printf("\t\tSkipping\n")
} else {
path := filepath.Join(originPath, dirName, fname)
f, err := os.Open(path)
if err != nil {
fmt.Printf("\t\tError while opening file %s! : %v\n", path, err)
}
originFiles[dirName] = append(originFiles[dirName], f)
}
}
}
}
return originFiles, nil
}
func main() {
flag.Parse()
if filepath.IsAbs(*originFlag) {
originPath = *originFlag
} else {
wd, err := os.Getwd()
if err != nil {
fmt.Printf("Error while retrieving working directory, please retry with an absolute path: %v\n", err)
return
}
originPath = filepath.Join(wd, *originFlag)
}
if filepath.IsAbs(*destinationFlag) {
destinationPath = *destinationFlag
} else {
wd, err := os.Getwd()
if err != nil {
fmt.Printf("Error while retrieving working directory, please retry with an absolute path: %v\n", err)
return
}
destinationPath = filepath.Join(wd, *destinationFlag)
}
originFiles, err := load(originPath)
if err != nil {
fmt.Printf("Error: %v", err)
}
// For each of them, process them
for cat, files := range originFiles {
cat = equivalence[cat]
fmt.Printf("Printing %s...\n", cat)
for _, file := range files {
fmt.Printf("Dealing with one origin-file...\n")
// Prepare decoder
dec := json.NewDecoder(file)
// Create hosting structure & decode to it
var req request
switch cat {
case "journey":
tmp := &journeyRequest{}
// Decode to it
err := dec.Decode(tmp)
if err != nil {
stat, _ := file.Stat()
fmt.Printf("Error while decoding %s: %v\n", stat.Name(), err)
return
}
req = tmp
case "place":
tmp := &placeRequest{}
// Decode to it
err := dec.Decode(tmp)
if err != nil {
stat, _ := file.Stat()
fmt.Printf("Error while decoding %s: %v\n", stat.Name(), err)
return
}
req = tmp
case "region":
tmp := &coverageRequest{}
// Decode to it
err := dec.Decode(tmp)
if err != nil {
stat, _ := file.Stat()
fmt.Printf("Error while decoding %s: %v\n", stat.Name(), err)
return
}
req = tmp
default:
fmt.Printf("Incorrect category")
return
}
// Get file stat
stat, err := file.Stat()
if err != nil {
fmt.Printf("Error while retrieving file stat: %v\n", err)
continue
}
// Now for each Journey, create a new file and write to it
for i, message := range req.messages() {
// Create the file name
nname := fmt.Sprintf("%s%d.json", stat.Name()[:len(stat.Name())-5], i)
npath := filepath.Join(destinationPath, cat, nname)
// Create the file
nfile, err := os.Create(npath)
if err != nil {
fmt.Printf("Error while creating file %s: %v\n", npath, err)
}
// Write to it
enc := json.NewEncoder(nfile)
enc.SetIndent("", "\t")
err = enc.Encode(message)
if err != nil {
fmt.Printf("Error while writing to file %s: %v\n", npath, err)
}
}
}
}
}

View File

@ -0,0 +1,23 @@
{
"id": "ce7e265d-5762-45b6-ab4d-a1df643dd48d",
"status": "active",
"disruption_id": "ce7e265d-5762-45b6-ab4d-a1df643dd48d",
"impact_id": "ce7e265d-5762-45b6-ab4d-a1df643dd48d",
"severity": {
"name": "trip delayed",
"effect": "SIGNIFICANT_DELAYS"
},
"application_periods": [
{
"begin": "20160608T215400",
"end": "20160608T230959"
}
],
"messages": [
{"text": "Strike"}
],
"updated_at": "20160617T132624",
"impacted_objects": [],
"cause": "Cause...",
"category": "incident"
}

File diff suppressed because it is too large Load Diff

2135
types/testdata/journey/bench/heavy.json vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,898 @@
{
"arrival_date_time": "20170413T141146",
"calendars": [
{
"active_periods": [
{
"begin": "20170326",
"end": "20170417"
}
],
"exceptions": [
{
"datetime": "20170402",
"type": "remove"
},
{
"datetime": "20170409",
"type": "remove"
},
{
"datetime": "20170415",
"type": "add"
}
],
"week_pattern": {
"friday": true,
"monday": true,
"saturday": false,
"sunday": true,
"thursday": true,
"tuesday": true,
"wednesday": true
}
}
],
"co2_emission": {
"unit": "gEC",
"value": 39.556
},
"departure_date_time": "20170413T133945",
"duration": 1921,
"durations": {
"total": 1921,
"walking": 1081
},
"fare": {
"found": false,
"links": [],
"total": {
"currency": "",
"value": "0.0"
}
},
"links": [
{
"href": "https://api.navitia.io/v1/coverage/fr-idf/journeys?allowed_id%5B%5D=stop_area%3AOIF%3ASA%3A8739305\u0026allowed_id%5B%5D=stop_area%3AOIF%3ASA%3A8754700\u0026to=2.2922926%3B48.8583736\u0026from=2.3749036%3B48.8467927\u0026min_nb_journeys=5",
"rel": "same_journey_schedules",
"templated": false,
"type": "journeys"
}
],
"nb_transfers": 0,
"requested_date_time": "20170413T133734",
"sections": [
{
"arrival_date_time": "20170413T135400",
"co2_emission": {
"unit": "",
"value": 0.0
},
"departure_date_time": "20170413T133945",
"duration": 855,
"from": {
"address": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
},
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"coord": {
"lat": "48.8467927",
"lon": "2.3749036"
},
"house_number": 9,
"id": "2.3749036;48.8467927",
"label": "9 Rue Abel (Paris)",
"name": "Rue Abel"
},
"embedded_type": "address",
"id": "2.3749036;48.8467927",
"name": "9 Rue Abel (Paris)",
"quality": 0
},
"id": "section_12_0",
"links": [],
"mode": "walking",
"path": [
{
"direction": 0,
"duration": 90,
"length": 101,
"name": "Rue Abel"
},
{
"direction": 22,
"duration": 14,
"length": 16,
"name": "Boulevard Diderot"
},
{
"direction": -7,
"duration": 328,
"length": 367,
"name": "Rue Van Gogh"
},
{
"direction": 8,
"duration": 40,
"length": 45,
"name": ""
},
{
"direction": -4,
"duration": 183,
"length": 205,
"name": "Pont Charles de Gaulle"
},
{
"direction": -6,
"duration": 13,
"length": 15,
"name": ""
},
{
"direction": 90,
"duration": 161,
"length": 180,
"name": "Quai d'Austerlitz"
},
{
"direction": -87,
"duration": 26,
"length": 29,
"name": ""
},
{
"direction": 0,
"duration": 0,
"length": 0,
"name": "Cour Seine"
}
],
"to": {
"embedded_type": "stop_point",
"id": "stop_point:OIF:SP:8754702:800:C",
"name": "Gare d'Austerlitz RER C (Paris)",
"quality": 0,
"stop_point": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41333"
},
{
"type": "external_code",
"value": "OIF8754702:800:C"
},
{
"type": "source",
"value": "StopPoint:8754702:800:C"
}
],
"commercial_modes": [
{
"id": "commercial_mode:rapidtransit",
"name": "RER"
}
],
"coord": {
"lat": "48.842528",
"lon": "2.365433"
},
"equipments": [],
"id": "stop_point:OIF:SP:8754702:800:C",
"label": "Gare d'Austerlitz RER C (Paris)",
"links": [],
"name": "Gare d'Austerlitz RER C",
"physical_modes": [
{
"id": "physical_mode:RapidTransit",
"name": "Train de banlieue / RER"
}
],
"stop_area": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"codes": [
{
"type": "external_code",
"value": "OIF8754700"
},
{
"type": "source",
"value": "StopArea:8754700"
}
],
"coord": {
"lat": "48.843578",
"lon": "2.364651"
},
"id": "stop_area:OIF:SA:8754700",
"label": "Gare d'Austerlitz (Paris)",
"links": [],
"name": "Gare d'Austerlitz",
"timezone": "Europe/Paris"
}
}
},
"type": "street_network"
},
{
"additional_informations": [
"regular"
],
"arrival_date_time": "20170413T140800",
"base_arrival_date_time": "20170413T140800",
"base_departure_date_time": "20170413T135400",
"co2_emission": {
"unit": "gEC",
"value": 39.556
},
"departure_date_time": "20170413T135400",
"display_informations": {
"code": "C",
"color": "FCD946",
"commercial_mode": "RER",
"description": "",
"direction": "Gare de Versailles Ch\u00e2teau - Rive Gauche (Versailles)",
"equipments": [],
"headsign": "VICK",
"label": "C",
"links": [],
"network": "RER",
"physical_mode": "Train de banlieue / RER",
"text_color": "FFFFFF"
},
"duration": 840,
"from": {
"embedded_type": "stop_point",
"id": "stop_point:OIF:SP:8754702:800:C",
"name": "Gare d'Austerlitz RER C (Paris)",
"quality": 0,
"stop_point": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41333"
},
{
"type": "external_code",
"value": "OIF8754702:800:C"
},
{
"type": "source",
"value": "StopPoint:8754702:800:C"
}
],
"coord": {
"lat": "48.842528",
"lon": "2.365433"
},
"equipments": [],
"id": "stop_point:OIF:SP:8754702:800:C",
"label": "Gare d'Austerlitz RER C (Paris)",
"links": [],
"name": "Gare d'Austerlitz RER C",
"stop_area": {
"codes": [
{
"type": "external_code",
"value": "OIF8754700"
},
{
"type": "source",
"value": "StopArea:8754700"
}
],
"coord": {
"lat": "48.843578",
"lon": "2.364651"
},
"id": "stop_area:OIF:SA:8754700",
"label": "Gare d'Austerlitz (Paris)",
"links": [],
"name": "Gare d'Austerlitz",
"timezone": "Europe/Paris"
}
}
},
"id": "section_13_0",
"links": [
{
"id": "vehicle_journey:OIF:82209457-1_354848-1_dst_2",
"type": "vehicle_journey"
},
{
"id": "line:OIF:800:COIF741",
"type": "line"
},
{
"id": "route:OIF:800:C_R",
"type": "route"
},
{
"id": "commercial_mode:rapidtransit",
"type": "commercial_mode"
},
{
"id": "physical_mode:RapidTransit",
"type": "physical_mode"
},
{
"id": "network:RER",
"type": "network"
}
],
"stop_date_times": [
{
"additional_informations": [],
"arrival_date_time": "20170413T135300",
"base_arrival_date_time": "20170413T135300",
"base_departure_date_time": "20170413T135400",
"departure_date_time": "20170413T135400",
"links": [],
"stop_point": {
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41333"
},
{
"type": "external_code",
"value": "OIF8754702:800:C"
},
{
"type": "source",
"value": "StopPoint:8754702:800:C"
}
],
"coord": {
"lat": "48.842528",
"lon": "2.365433"
},
"equipments": [],
"id": "stop_point:OIF:SP:8754702:800:C",
"label": "Gare d'Austerlitz RER C (Paris)",
"links": [],
"name": "Gare d'Austerlitz RER C"
}
},
{
"additional_informations": [],
"arrival_date_time": "20170413T135700",
"base_arrival_date_time": "20170413T135700",
"base_departure_date_time": "20170413T135800",
"departure_date_time": "20170413T135800",
"links": [],
"stop_point": {
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41335"
},
{
"type": "external_code",
"value": "OIF8754731:800:C"
},
{
"type": "source",
"value": "StopPoint:8754731:800:C"
}
],
"coord": {
"lat": "48.853336",
"lon": "2.346035"
},
"equipments": [],
"id": "stop_point:OIF:SP:8754731:800:C",
"label": "Saint-Michel Notre-Dame RER C (Paris)",
"links": [],
"name": "Saint-Michel Notre-Dame RER C"
}
},
{
"additional_informations": [],
"arrival_date_time": "20170413T140000",
"base_arrival_date_time": "20170413T140000",
"base_departure_date_time": "20170413T140100",
"departure_date_time": "20170413T140100",
"links": [],
"stop_point": {
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41334"
},
{
"type": "external_code",
"value": "OIF8754730:800:C"
},
{
"type": "source",
"value": "StopPoint:8754730:800:C"
}
],
"coord": {
"lat": "48.860708",
"lon": "2.32562"
},
"equipments": [],
"id": "stop_point:OIF:SP:8754730:800:C",
"label": "Mus\u00e9e d'Orsay (Paris)",
"links": [],
"name": "Mus\u00e9e d'Orsay"
}
},
{
"additional_informations": [],
"arrival_date_time": "20170413T140300",
"base_arrival_date_time": "20170413T140300",
"base_departure_date_time": "20170413T140400",
"departure_date_time": "20170413T140400",
"links": [],
"stop_point": {
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41208"
},
{
"type": "external_code",
"value": "OIF8739303:800:C"
},
{
"type": "source",
"value": "StopPoint:8739303:800:C"
}
],
"coord": {
"lat": "48.862902",
"lon": "2.313911"
},
"equipments": [],
"id": "stop_point:OIF:SP:8739303:800:C",
"label": "Invalides (Paris)",
"links": [],
"name": "Invalides"
}
},
{
"additional_informations": [],
"arrival_date_time": "20170413T140600",
"base_arrival_date_time": "20170413T140600",
"base_departure_date_time": "20170413T140600",
"departure_date_time": "20170413T140600",
"links": [],
"stop_point": {
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41209"
},
{
"type": "external_code",
"value": "OIF8739304:800:C"
},
{
"type": "source",
"value": "StopPoint:8739304:800:C"
}
],
"coord": {
"lat": "48.862662",
"lon": "2.30099"
},
"equipments": [],
"id": "stop_point:OIF:SP:8739304:800:C",
"label": "Pont de l'Alma (Paris)",
"links": [],
"name": "Pont de l'Alma"
}
},
{
"additional_informations": [],
"arrival_date_time": "20170413T140800",
"base_arrival_date_time": "20170413T140800",
"base_departure_date_time": "20170413T140900",
"departure_date_time": "20170413T140900",
"links": [],
"stop_point": {
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41210"
},
{
"type": "external_code",
"value": "OIF8739305:800:C"
},
{
"type": "source",
"value": "StopPoint:8739305:800:C"
}
],
"coord": {
"lat": "48.857293",
"lon": "2.290392"
},
"equipments": [],
"id": "stop_point:OIF:SP:8739305:800:C",
"label": "Champ de Mars Tour Eiffel (Paris)",
"links": [],
"name": "Champ de Mars Tour Eiffel"
}
}
],
"to": {
"embedded_type": "stop_point",
"id": "stop_point:OIF:SP:8739305:800:C",
"name": "Champ de Mars Tour Eiffel (Paris)",
"quality": 0,
"stop_point": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41210"
},
{
"type": "external_code",
"value": "OIF8739305:800:C"
},
{
"type": "source",
"value": "StopPoint:8739305:800:C"
}
],
"coord": {
"lat": "48.857293",
"lon": "2.290392"
},
"equipments": [],
"id": "stop_point:OIF:SP:8739305:800:C",
"label": "Champ de Mars Tour Eiffel (Paris)",
"links": [],
"name": "Champ de Mars Tour Eiffel",
"stop_area": {
"codes": [
{
"type": "external_code",
"value": "OIF8739305"
},
{
"type": "source",
"value": "StopArea:8739305"
}
],
"coord": {
"lat": "48.8572",
"lon": "2.293234"
},
"id": "stop_area:OIF:SA:8739305",
"label": "Champ de Mars Tour Eiffel (Paris)",
"links": [],
"name": "Champ de Mars Tour Eiffel",
"timezone": "Europe/Paris"
}
}
},
"type": "public_transport"
},
{
"arrival_date_time": "20170413T141146",
"co2_emission": {
"unit": "",
"value": 0.0
},
"departure_date_time": "20170413T140800",
"duration": 226,
"from": {
"embedded_type": "stop_point",
"id": "stop_point:OIF:SP:8739305:800:C",
"name": "Champ de Mars Tour Eiffel (Paris)",
"quality": 0,
"stop_point": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
},
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"codes": [
{
"type": "ZDEr_ID_REF_A",
"value": "41210"
},
{
"type": "external_code",
"value": "OIF8739305:800:C"
},
{
"type": "source",
"value": "StopPoint:8739305:800:C"
},
{
"type": "ZDEr_ID_REF_A",
"value": "41210"
},
{
"type": "external_code",
"value": "OIF8739305:800:C"
},
{
"type": "source",
"value": "StopPoint:8739305:800:C"
}
],
"commercial_modes": [
{
"id": "commercial_mode:rapidtransit",
"name": "RER"
}
],
"coord": {
"lat": "48.857293",
"lon": "2.290392"
},
"equipments": [],
"id": "stop_point:OIF:SP:8739305:800:C",
"label": "Champ de Mars Tour Eiffel (Paris)",
"links": [],
"name": "Champ de Mars Tour Eiffel",
"physical_modes": [
{
"id": "physical_mode:RapidTransit",
"name": "Train de banlieue / RER"
}
],
"stop_area": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"codes": [
{
"type": "external_code",
"value": "OIF8739305"
},
{
"type": "source",
"value": "StopArea:8739305"
},
{
"type": "external_code",
"value": "OIF8739305"
},
{
"type": "source",
"value": "StopArea:8739305"
}
],
"coord": {
"lat": "48.8572",
"lon": "2.293234"
},
"id": "stop_area:OIF:SA:8739305",
"label": "Champ de Mars Tour Eiffel (Paris)",
"links": [],
"name": "Champ de Mars Tour Eiffel",
"timezone": "Europe/Paris"
}
}
},
"id": "section_14_0",
"links": [],
"mode": "walking",
"path": [
{
"direction": 0,
"duration": 19,
"length": 21,
"name": ""
},
{
"direction": 0,
"duration": 14,
"length": 16,
"name": ""
},
{
"direction": 3,
"duration": 5,
"length": 6,
"name": ""
},
{
"direction": 13,
"duration": 28,
"length": 31,
"name": ""
},
{
"direction": -101,
"duration": 3,
"length": 3,
"name": ""
},
{
"direction": -4,
"duration": 5,
"length": 6,
"name": ""
},
{
"direction": 3,
"duration": 3,
"length": 3,
"name": ""
},
{
"direction": -89,
"duration": 17,
"length": 19,
"name": ""
},
{
"direction": 93,
"duration": 132,
"length": 148,
"name": "Quai Branly"
}
],
"to": {
"address": {
"administrative_regions": [
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
},
{
"coord": {
"lat": "48.856609",
"lon": "2.351499"
},
"id": "admin:fr:75056",
"insee": "75056",
"label": "Paris",
"level": 8,
"name": "Paris",
"zip_code": ""
}
],
"coord": {
"lat": "48.8583736",
"lon": "2.2922926"
},
"house_number": 69,
"id": "2.2922926;48.8583736",
"label": "69 Quai Branly (Paris)",
"name": "Quai Branly"
},
"embedded_type": "address",
"id": "2.2922926;48.8583736",
"name": "69 Quai Branly (Paris)",
"quality": 0
},
"type": "street_network"
}
],
"status": "",
"tags": [
"walking",
"ecologic"
],
"type": "best"
}

1112
types/testdata/journey/bench/light.json vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1863
types/testdata/journey/bench/regular.json vendored Normal file

File diff suppressed because it is too large Load Diff

2135
types/testdata/journey/correct/a0.json vendored Normal file

File diff suppressed because it is too large Load Diff

1863
types/testdata/journey/correct/a1.json vendored Normal file

File diff suppressed because it is too large Load Diff

1564
types/testdata/journey/correct/a2.json vendored Normal file

File diff suppressed because it is too large Load Diff

1112
types/testdata/journey/correct/b0.json vendored Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More