diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79cd018..78d00a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 - name: Setup Ruby uses: ruby/setup-ruby@v1 @@ -29,5 +29,10 @@ jobs: run: bundle exec standardrb - name: Run tests + # SimpleCov laeuft nur mit COVERAGE=1 -- ohne das hier greift auch die + # Untergrenze aus spec_helper.rb nicht, und ein Absturz der Abdeckung + # liefe still durch. + env: + COVERAGE: 1 run: | bundle exec rspec diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ffbae6..3fe4512 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,6 +80,11 @@ jobs: run: bundle exec standardrb - name: Run tests + # SimpleCov laeuft nur mit COVERAGE=1 -- ohne das hier greift auch die + # Untergrenze aus spec_helper.rb nicht, und ein Absturz der Abdeckung + # liefe still durch. + env: + COVERAGE: 1 run: bundle exec rspec - name: Release erstellen diff --git a/Gemfile.lock b/Gemfile.lock index 08574a6..9876f67 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -52,6 +52,7 @@ GEM rubocop (>= 1.75.0, < 2.0) rubocop-ast (>= 1.47.1, < 2.0) ruby-progressbar (1.13.0) + simplecov (1.3.0) standard (1.55.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) @@ -75,6 +76,7 @@ DEPENDENCIES bundler (>= 2.0) rake rspec (~> 3.0) + simplecov standard zip-codes! diff --git a/lib/data/DE.yml b/lib/data/DE.yml index 7e7b18f..b88a6f9 100644 --- a/lib/data/DE.yml +++ b/lib/data/DE.yml @@ -4595,7 +4595,7 @@ '22929': :osm_id: '454243' :code: '22929' - :city: Schönberg;Rausdorf;Köthel;Köthel;Kasseburg;Hamfelde + :city: Schönberg;Rausdorf;Köthel;Kasseburg;Hamfelde :county: Kreis Stormarn :state: Schleswig-Holstein '22941': diff --git a/lib/zip-codes/city_map.rb b/lib/zip-codes/city_map.rb index acee57c..ebf3784 100644 --- a/lib/zip-codes/city_map.rb +++ b/lib/zip-codes/city_map.rb @@ -29,10 +29,15 @@ def store! private # allow multiple cities for one code + # + # Beide Seiten werden zerlegt, bevor uniq greift. Der bestehende Wert ist ab + # der zweiten Stadt selbst zusammengesetzt ("A;B"); ungeteilt verglichen ist + # er ein einziger Eintrag, und uniq erkennt eine erneut gemeldete Stadt dann + # nicht wieder. In DE.yml stand so "Koethel" zweimal in derselben Zeile. def update_existing(code, data) map[code][:city] = [ *data[:city].to_s.split(";"), - map[code][:city] + *map[code][:city].to_s.split(";") ].uniq.join(";") end diff --git a/spec/lib/zip-codes/city_map_spec.rb b/spec/lib/zip-codes/city_map_spec.rb new file mode 100644 index 0000000..15aae1c --- /dev/null +++ b/spec/lib/zip-codes/city_map_spec.rb @@ -0,0 +1,75 @@ +require "tmpdir" + +RSpec.describe ZipCodes::CityMap do + subject(:karte) { described_class.new(datei) } + + let(:datei) { File.join(Dir.tmpdir, "city_map_spec.yml") } + let(:hamburg) { {osm_id: "62782", city: "Hamburg", county: "Hamburg-Mitte", state: "Hamburg"} } + + after { File.delete(datei) if File.exist?(datei) } + + describe "#add" do + it "legt einen neuen Eintrag mit allen Feldern an" do + karte.add("20535", hamburg) + + expect(karte.map["20535"]).to eq( + osm_id: "62782", code: "20535", city: "Hamburg", + county: "Hamburg-Mitte", state: "Hamburg" + ) + end + + it "verlangt die Pflichtfelder" do + expect { karte.add("20535", {city: "Hamburg"}) }.to raise_error(KeyError) + end + + it "haengt eine zweite Stadt an denselben Code an" do + karte.add("20535", hamburg) + karte.add("20535", {city: "Altona"}) + + expect(karte.map["20535"][:city]).to eq("Altona;Hamburg") + end + + # Der Fall, der in DE.yml ein doppeltes "Koethel" erzeugt hat: ab der + # zweiten Stadt ist der bestehende Wert selbst zusammengesetzt. Wird er + # ungeteilt verglichen, erkennt uniq eine erneut gemeldete Stadt nicht. + it "nimmt eine bereits eingetragene Stadt kein zweites Mal auf" do + karte.add("20535", hamburg) + karte.add("20535", {city: "Altona"}) + karte.add("20535", {city: "Hamburg"}) + + expect(karte.map["20535"][:city]).to eq("Hamburg;Altona") + end + + it "zerlegt auch mehrere Staedte in einer Angabe" do + karte.add("20535", hamburg) + karte.add("20535", {city: "Altona;Hamburg"}) + + expect(karte.map["20535"][:city]).to eq("Altona;Hamburg") + end + end + + describe "#to_yaml" do + it "gibt die Karte als YAML zurueck" do + karte.add("20535", hamburg) + + expect(YAML.safe_load(karte.to_yaml, permitted_classes: [Symbol])).to eq( + "20535" => { + osm_id: "62782", code: "20535", city: "Hamburg", + county: "Hamburg-Mitte", state: "Hamburg" + } + ) + end + end + + describe "#store! und #load!" do + it "schreibt die Karte und liest sie unveraendert zurueck" do + karte.add("20535", hamburg) + karte.store! + + gelesen = described_class.new(datei) + gelesen.load! + + expect(gelesen.map).to eq(karte.map) + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b584841..50f302e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,14 @@ +# Abdeckungsmessung nur auf Wunsch: COVERAGE=1 bundle exec rspec +if ENV["COVERAGE"] + require "simplecov" + SimpleCov.start do + add_filter "/spec/" + # Schwelle knapp unter dem Ist-Stand (100 %), damit sie einen Absturz + # wirklich faengt. Steigt die Abdeckung dauerhaft, darf sie mitwachsen. + minimum_coverage 95 + end +end + require "bundler/setup" require "zip-codes" diff --git a/zip-codes.gemspec b/zip-codes.gemspec index 68ccb08..e85ac86 100644 --- a/zip-codes.gemspec +++ b/zip-codes.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rake" spec.add_development_dependency "rspec", "~> 3.0" spec.add_development_dependency "standard" + spec.add_development_dependency "simplecov" spec.required_ruby_version = ">= 3.1.0" end