<commit_before># frozen_string_literal: true

require_relative "../rails_helper"

RSpec.describe Work, type: :model do
  describe "callbacks" do
    describe "artist_name" do
      it "should keep a log of changed artists" do
        w = works(:work1)
        w.save # saving just to make the diff smaller
        w.artists << artists(:artist2)
        w.save
        change_set = YAML.load(w.versions.last.object_changes) # standard:disable Security/YAMLLoad # object_changes is created by papertrail
        artist_name_for_sorting_changes = change_set["artist_name_for_sorting"]
        expect(artist_name_for_sorting_changes[0]).to eq("artist_1, firstname")
        expect(artist_name_for_sorting_changes[1].split(";")).to match_array(["artist_1, firstname", "artist_2 achternaam, firstie"])
      end
    end
    describe "significantly_updated_at" do
      it "does not update when nothing changed" do
        w = works(:work1)
        expect {
          w.save
        }.not_to change(w, :significantly_updated_at)
      end
      it "does update on create" do
        w = collections(:collection1).works.create
        expect(w.significantly_updated_at.to_date).to eq(w.created_at.to_date)
      end
      it "does update on a title change" do
        w = works(:work1)
        expect {
          w.title = "abc"
          w.save
        }.to change(w, :significantly_updated_at)
        w = works(:work1)
        expect {
          w.update(title: "abca")
        }.to change(w, :significantly_updated_at)
      end
      it "does update on a artist change" do
        w = works(:work1)
        expect {
          w.artists << artists(:artist2)
          w.save
        }.to change(w, :significantly_updated_at)
      end
    end
  end
  describe "instance methods" do
    describe "#all_work_ids_in_collection" do
      it "sorts by default on inventory and id" do
        w = works(:work1)
        expect(w.all_work_ids_in_collection.count).to eq 3
        expect(w.work_index_in_collection).to eq(0)
        w = works(:work5)
        expect(w.all_work_ids_in_collection.count).to eq 3
        expect(w.work_index_in_collection).to eq(2)
      end
      it "can sort on super collection" do
        w = works(:work1)
        parent = w.collection.parent_collection
        parent.sort_works_by = :inventoried_at
        parent.save
        expect(w.all_work_ids_in_collection.count).to eq 5
        expect(w.work_index_in_collection).to eq(1)
        w = works(:work2)
        expect(w.all_work_ids_in_collection.count).to eq 5
        expect(w.work_index_in_collection).to eq(0)
      end
    end
    describe "#appraisable?" do
      it "should return true by default" do
        expect(works(:work1)).to be_appraisable
      end
      it "should return false on a work part of a diptych" do
        expect(works(:work_diptych_1)).not_to be_appraisable
      end
    end
    describe "#artist_#\{index\}_methods" do
      it "should have a first artist" do
        w = works(:work1)
        expect(w.artist_0_last_name).to eq("artist_1")
        expect(w.artist_0_first_name).to eq("firstname")
      end
      it "should return nil when no artist is found at index" do
        w = works(:work1)
        expect(w.artist_4_last_name).to eq(nil)
        expect(w.artist_4_first_name).to eq(nil)
      end
    end
    describe "#frame_type" do
      it "should be able to set a FrameType" do
        w = works(:work1)
        w.frame_type = FrameType.create(name: "test")
        w.save
        expect(w.frame_type.name).to eq("test")
      end
    end
    describe "#stock_number_file_safe" do
      it "should not change good number" do
        expect(Work.new(stock_number: 123).stock_number_file_safe).to eq "123"
      end
      it "should change risky number" do
        expect(Work.new(stock_number: "12/3").stock_number_file_safe).to eq "12-3"
        expect(Work.new(stock_number: "12//3").stock_number_file_safe).to eq "12--3"
        expect(Work.new(stock_number: "1:\\2//3").stock_number_file_safe).to eq "1--2--3"
      end
    end
    describe "#height" do
      it "should accept integer" do
        w = works(:work1)
        w.height = 1
        w.save
        w.reload
        expect(w.height).to eq 1.0
      end
      it "should accept string" do
        w = works(:work1)
        w.height = "12"
        w.save
        w.reload
        expect(w.height).to eq 12.0
      end
      it "should accept us-localized string" do
        w = works(:work1)
        w.height = "12.1"
        w.save
        w.reload
        expect(w.height).to eq 12.1
      end
      it "should accept nl-localized string" do
        w = works(:work1)
        w.height = "12,1"
        w.save
        w.reload
        expect(w.height).to eq 12.1
      end
      it "should accept long nl-localized string" do
        w = works(:work1)
        w.height = "12.012,1"
        w.save
        w.reload
        expect(w.height).to eq 12012.1
      end
    end
    describe "#purchased_on=" do
      it "should accept a date" do
        w = works(:work1)
        date = Date.new(1978, 12, 22)
        w.purchased_on = date
        w.save
        w.reload
        expect(w.purchased_on).to eq(date)
        expect(w.purchase_year).to eq(1978)
      end
      it "should not fail on an empty string" do
        w = works(:work1)
        w.purchased_on = ""
        w.save
        w.reload
        expect(w.purchased_on).to eq(nil)
        expect(w.purchase_year).to eq(nil)
      end
      it "should accept a string" do
        w = works(:work1)
        date = Date.new(1978, 12, 22)
        date_string = date.to_s
        w.purchased_on = date_string
        w.save
        w.reload
        expect(w.purchased_on).to eq(date)
        expect(w.purchase_year).to eq(1978)
      end
      it "should accept a nil" do
        w = works(:work1)
        w.purchased_on = nil
        w.save
        w.reload
        expect(w.purchased_on).to be_nil
      end
      it "should accept a number" do
        w = works(:work1)
        date = 2012
        w.purchased_on = date
        w.save
        w.reload
        expect(w.purchased_on).to eq(nil)
        expect(w.purchase_year).to eq(2012)
      end
      it "should accept a number in a string" do
        w = works(:work1)
        date = "2012"
        w.purchased_on = date
        w.save
        w.reload
        expect(w.purchased_on).to eq(nil)
        expect(w.purchase_year).to eq(2012)
      end
    end
    describe "#damage_types" do
      it "should be an empty by default" do
        w = works(:work2)
        expect(w.damage_types).to eq([])
      end
      it "should should touch work on add (and should only return once)" do
        w = works(:work2)
        original_updated_at = w.updated_at
        w.damage_types << damage_types(:a)
        w.damage_types << damage_types(:a)
        expect(w.damage_types).to match_array([damage_types(:a)])
        expect(w.updated_at - original_updated_at).to be > 0.001
      end
    end
    describe "#cluster_name" do
      it "should set cluster to nil when name is nil or empty" do
        w = works(:work1)
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = ""
        expect(w.cluster).to eq(nil)
        w = works(:work1)
        w.reload
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = nil
        expect(w.cluster).to eq(nil)
        w.save
        w.reload
        w = works(:work1)
        expect(w.cluster).to eq(nil)
      end
      it "should reset cluster when set to a different name" do
        w = works(:work1)
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = "cluster2"
        expect(w.cluster).to eq(clusters(:cluster2))
        w.save
        w.reload
        expect(w.cluster).to eq(clusters(:cluster2))
      end
      it "should create cluster when set to a different name" do
        w = works(:work1)
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = "cluster new"
        expect(w.cluster.class).to eq(Cluster)
        w.save
        w.reload
        expect(w.cluster_name).to eq("cluster new")
      end
    end

    describe "#location_description" do
      it "concats the location fields" do
        expect(works(:work1).location_description).to eq("Adres; Floor 1; Room 1")
      end
      it "returns emtpy string when none" do
        expect(Work.new.location_description).to eq(nil)
      end
    end
    describe "#location_history" do
      it "returns an empty array if no history" do
        expect(works(:work1).location_history).to eq([])
      end
      it "returns a single item array if no history" do
        work1 = works(:work1)
        work1.location = "New adress"
        work1.save
        work1.location = "Newer address"
        work1.save
        expect(works(:work1).location_history.collect { |a| a[:location] }).to eq(["New adress", "Newer address"])
      end
      it "returns complete history if work is created after enabling history" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = "second location"
        work.save
        work.location = "third location"
        work.save
        expect(work.location_history.collect { |a| a[:location] }).to eq(["first location", "second location", "third location"])
      end
      it "skip_current options skips current" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = "second location"
        work.save
        expect(work.location_history(skip_current: true).collect { |a| a[:location] }).to eq(["first location"])
      end
      it "returns empty location if empty location" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = nil
        work.save
        expect(work.location_history.collect { |a| a[:location] }).to eq(["first location", nil])
      end
      it "never returns empty location if empty location and no empty locations" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = ""
        work.save
        expect(work.location_history(empty_locations: false).collect { |a| a[:location] }).to eq(["first location"])
      end
      it "never returns empty location if empty location and no empty locations (and doesn't just pop the skip current false)" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = ""
        work.save
        expect(work.location_history(empty_locations: false, skip_current: true).collect { |a| a[:location] }).to eq(["first location"])
      end
    end
    describe "#purchased_on_with_fallback" do
      it "should return nil when not set" do
        w = works(:work1)
        expect(w.purchased_on_with_fallback).to eq(nil)
      end
      it "should return date both year and date are present" do
        w = works(:work1)
        w.purchased_on = Date.new(1978, 12, 22)
        w.purchase_year = 1978
        expect(w.purchased_on_with_fallback).to eq(Date.new(1978, 12, 22))
      end
      it "should return year if only year is present" do
        w = works(:work1)
        w.purchase_year = 1978
        expect(w.purchased_on_with_fallback).to eq(1978)
      end
    end
    describe "#next" do
      it "should redirect to the next work" do
        w = works(:work1)
        expect(w.next).to eq(works(:work2))
        expect(w.next.next).to eq(works(:work5))
      end
      it "should return first if no next" do
        expect(works(:work5).next).to eq(works(:work1))
      end
    end
    describe "#previous" do
      it "should redirect to the previous work" do
        w = works(:work5)
        expect(w.previous).to eq(works(:work2))
        expect(w.previous.previous).to eq(works(:work1))
      end
      it "should return last if no previous" do
        expect(works(:work1).previous).to eq(works(:work5))
      end
    end
    describe "#object_creation_year" do
      it "should return nil if object_creation_year_unknown = true" do
        w = works(:work2)
        w.object_creation_year = 2012
        w.save
        w.reload
        expect(w.object_creation_year).to eq(2012)
        w.object_creation_year_unknown = true
        w.save
        w.reload
        expect(w.object_creation_year).to eq(nil)
      end
    end
    describe "#object_format_code" do
      it "should return proper format code" do
        expect(works(:work2).object_format_code).to eq(nil)
        w = works(:work2)
        w.height = 200
        expect(w.object_format_code).to eq(:xl)
        w.height = 90
        expect(w.object_format_code).to eq(:l)
      end
    end
    describe "#frame_size_with_fallback" do
      it "should return frame size by default" do
        expect(works(:work1).frame_size_with_fallback).to eq(works(:work1).frame_size)
        expect(works(:work2).frame_size_with_fallback).to eq(nil)
        # expect(works(:work2).frame_size_with_fallback).to eq(works(:work2).frame_size)
      end
      it "should return work size if frame size is not present" do
        w = works(:work2)
        w.height = 90
        w.width = 180
        expect(works(:work2).frame_size_with_fallback).not_to eq(nil)
        expect(works(:work2).frame_size_with_fallback).to eq("180 × 90 (b×h)")
      end
    end
    describe "#restore_last_location_if_blank!" do
      it "shoudl restore last location when blenk" do
        w = collections(:collection1).works.create(location: "first location")

        original_location_description = w.location_description
        w.location = nil
        w.location_floor = nil
        w.location_detail = nil
        w.save

        expect(w.location_description).to eq(nil)
        expect(w.versions.last.reify.location_description).to eq(original_location_description)
        w.restore_last_location_if_blank!
        w.reload
        expect(w.location_description).to eq(original_location_description)
      end
      it "should not 'restore' a location if location is set" do
        w = collections(:collection1).works.create(location: "first location")
        w.location = "new location"
        w.save
        w.restore_last_location_if_blank!
        w.reload
        expect(w.location_description).to eq("new location")
      end
    end
    describe "#save" do
      it "should save, even without info" do
        w = collections(:collection1).works.new
        w.save
        expect(w.id).to be > 1
      end
      # it "should save, even with just comments set" do
      #   w = Work.new
      #   w.save
      #   expect(w.id).to be > 1
      # end
    end
    describe "public_tag_list" do
      it "filters public tags" do
        w = Work.create(collection: collections(:collection1), tag_list: %(inventariseren 2020, vermist, 1984, blauw, bekijKen op, aangetroffen, naar fotograaf, selectie, H3 definitief, ontzamelen, aankopen, herplaatsen, navragen, Herplaatsing, Industrie))
        expect(w.public_tag_list).to eq(["1984", "blauw", "Industrie"])
      end
    end
    describe "work_set_attributes=" do
      it "ignores empty hashes" do
        w = Work.create(work_set_attributes: {})
        expect(w.work_sets.count).to eq(0)
      end
      it "ignores partially empty hashes" do
        w = Work.create(work_set_attributes: {identification_number: 123})
        expect(w.work_sets.count).to eq(0)
      end
      it "creates when full hash is given" do
        w = Work.new
        expect {
          w = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect(w.work_sets.count).to eq(1)
      end
      it "reuses when full hash is given equal to earlier in same collection" do
        w1 = Work.new
        w2 = Work.new
        expect {
          w1 = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect {
          w2 = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(0)
        expect(w1.work_sets.count).to eq(1)
        expect(w2.work_sets.count).to eq(1)
        w2.work_sets.reload
        expect(w2.work_sets.first.work_ids).to match_array([w1, w2].map(&:id))
      end
      it "creates when full hash is given equal to earlier in other collection" do
        w1 = Work.new
        w2 = Work.new
        expect {
          w1 = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect {
          w2 = Work.create(collection: collections(:collection2), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect(w1.work_sets.count).to eq(1)
        expect(w2.work_sets.count).to eq(1)

        w1.work_sets.reload
        w2.work_sets.reload

        expect(w1.work_sets.first.work_ids).not_to include(w2.id)
        expect(w2.work_sets.first.work_ids).not_to include(w1.id)
      end
    end
  end
  describe "class methods" do
    describe ".artist_name_rendered" do
      it "should not fail on an empty name" do
        w = Work.new
        w.save
        expect(w.artist_name_rendered).to eq(nil)
      end
      it "should summarize the artists nicely" do
        w = works(:work1)
        w.save
        w.reload
        expect(w.artist_name_rendered).to eq("artist_1, firstname (1900 - 2000)")
      end
      it "should respect include_years option" do
        works(:work1).save
        expect(works(:work1).artist_name_rendered(include_years: false)).to eq("artist_1, firstname")
      end
    end
    describe ".artist_name_rendered_without_years_nor_locality" do
      it "should summarize the artist nicely" do
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality).to eq("artist_1, firstname")
      end
      it "should summarize the artists nicely" do
        works(:work1).artists << artists(:artist2)
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_1, firstname")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_2 achternaam, firstie")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match(";")
      end
    end
    describe ".artist_name_rendered_without_years_nor_locality_semicolon_separated" do
      it "should summarize the artist nicely" do
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to eq("artist_1, firstname")
      end
      it "should summarize the artists nicely" do
        works(:work1).artists << artists(:artist2)
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_1, firstname")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_2 achternaam, firstie")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match(";")
      end
    end

    describe ".count_as_whole_works" do
      it "should return all works uniquele" do
        work_count = Work.count
        works_in_worksets_counted_as_one = WorkSet.count_as_one.flat_map { |a| a.works.pluck(:id) }.uniq.count
        worksets_counted_as_one = WorkSet.count_as_one.count

        expect(Work.count_as_whole_works).to eq(work_count - works_in_worksets_counted_as_one + worksets_counted_as_one)
      end

      it "should return all works uniquely even when in two work sets" do
        work_count = Work.count
        works_in_worksets_counted_as_one = WorkSet.count_as_one.flat_map { |a| a.works.pluck(:id) }.uniq.count
        worksets_counted_as_one = WorkSet.count_as_one.count

        WorkSet.create(work_set_type: work_set_types(:possible_same_artist), works: [works(:work_diptych_1), works(:artistless_work)])

        expect(Work.count_as_whole_works).to eq(work_count - works_in_worksets_counted_as_one + worksets_counted_as_one)
      end
    end
    describe ".possible_exposable_fields" do
      it "should return possible_exposable_fields" do
        expect(Work.possible_exposable_fields).to include("owner")
        expect(Work.possible_exposable_fields).to include("location_detail")
        expect(Work.possible_exposable_fields).to include("location_floor")
      end
    end

    describe ".fast_aggregations" do
      it "should allow to be initialized" do
        works(:work1)
        works(:work2)
        aggregations = Work.fast_aggregations [:title, :themes, :subset, :grade_within_collection]
        expect(aggregations.count).to eq 4
        expect(aggregations[:title]["Work1"][:count]).to eq 999999
        expect(aggregations[:themes][themes(:wind)][:count]).to eq 999999
        expect(aggregations[:grade_within_collection]["A"][:count]).to eq 999999
        expect(aggregations[:grade_within_collection]["H"]).to eq nil
      end
    end
    describe ".whd_to_s" do
      it "should render nil if all are nil" do
        expect(Work.new.whd_to_s).to eq(nil)
      end
      it "should render w x h x d if set" do
        expect(Work.new.whd_to_s(1, 2, 3)).to eq("1 × 2 × 3 (b×h×d)")
      end
      it "should round w x h x d" do
        expect(Work.new.whd_to_s(1.002345, 2.2323543, 3.777777)).to eq("1,0023 × 2,2324 × 3,7778 (b×h×d)")
      end
      it "should add diameter if set" do
        expect(Work.new.whd_to_s(1, 2, 3, 4)).to eq("1 × 2 × 3 (b×h×d); ⌀ 4")
      end
      it "should add diameter if set" do
        expect(Work.new.whd_to_s(1, nil, 3, 4)).to eq("1 × 3 (b×d); ⌀ 4")
      end
    end
    describe ".frame_size" do
      it "should use whd_to_s" do
        expect(Work.new(frame_width: 1, frame_height: nil, frame_depth: 3, frame_diameter: 4).frame_size).to eq("1 × 3 (b×d); ⌀ 4")
      end
    end
    describe ".to_workbook" do
      it "should be callable and return a workbook" do
        expect(Work.to_workbook.class).to eq(Workbook::Book)
      end
      it "should be work even with complex fieldset" do
        collection = collections(:collection4)

        expect(Work.to_workbook(collection.fields_to_expose(:default)).class).to eq(Workbook::Book)
      end
      it "should work with tags" do
        collection = collections(:collection_with_works)
        work = collection.works.first
        work.tag_list = "kaas"
        work.save
        expect(Work.to_workbook(collection.fields_to_expose(:default)).class).to eq(Workbook::Book)
      end
      it "should return basic types" do
        collection = collections(:collection_with_works)
        work = collection.works.order(:stock_number).first
        work.save
        workbook = collection.works.order(:stock_number).to_workbook(collection.fields_to_expose(:default))
        expect(workbook.class).to eq(Workbook::Book)
        expect(workbook.sheet.table[1][:inventarisnummer].value).to eq(work.stock_number)
        expect(work.artists.first.name).to eq("artist_1, firstname (1900 - 2000)")
        expect(workbook.sheet.table[1][:vervaardigers].value).to eq("artist_1, firstname")<commit_msg>spec for order by location (seems to work though)<commit_after># frozen_string_literal: true

require_relative "../rails_helper"

RSpec.describe Work, type: :model do
  describe "callbacks" do
    describe "artist_name" do
      it "should keep a log of changed artists" do
        w = works(:work1)
        w.save # saving just to make the diff smaller
        w.artists << artists(:artist2)
        w.save
        change_set = YAML.load(w.versions.last.object_changes) # standard:disable Security/YAMLLoad # object_changes is created by papertrail
        artist_name_for_sorting_changes = change_set["artist_name_for_sorting"]
        expect(artist_name_for_sorting_changes[0]).to eq("artist_1, firstname")
        expect(artist_name_for_sorting_changes[1].split(";")).to match_array(["artist_1, firstname", "artist_2 achternaam, firstie"])
      end
    end
    describe "significantly_updated_at" do
      it "does not update when nothing changed" do
        w = works(:work1)
        expect {
          w.save
        }.not_to change(w, :significantly_updated_at)
      end
      it "does update on create" do
        w = collections(:collection1).works.create
        expect(w.significantly_updated_at.to_date).to eq(w.created_at.to_date)
      end
      it "does update on a title change" do
        w = works(:work1)
        expect {
          w.title = "abc"
          w.save
        }.to change(w, :significantly_updated_at)
        w = works(:work1)
        expect {
          w.update(title: "abca")
        }.to change(w, :significantly_updated_at)
      end
      it "does update on a artist change" do
        w = works(:work1)
        expect {
          w.artists << artists(:artist2)
          w.save
        }.to change(w, :significantly_updated_at)
      end
    end
  end
  describe "instance methods" do
    describe "#all_work_ids_in_collection" do
      it "sorts by default on inventory and id" do
        w = works(:work1)
        expect(w.all_work_ids_in_collection.count).to eq 3
        expect(w.work_index_in_collection).to eq(0)
        w = works(:work5)
        expect(w.all_work_ids_in_collection.count).to eq 3
        expect(w.work_index_in_collection).to eq(2)
      end
      it "can sort on super collection" do
        w = works(:work1)
        parent = w.collection.parent_collection
        parent.sort_works_by = :inventoried_at
        parent.save
        expect(w.all_work_ids_in_collection.count).to eq 5
        expect(w.work_index_in_collection).to eq(1)
        w = works(:work2)
        expect(w.all_work_ids_in_collection.count).to eq 5
        expect(w.work_index_in_collection).to eq(0)
      end
    end
    describe "#appraisable?" do
      it "should return true by default" do
        expect(works(:work1)).to be_appraisable
      end
      it "should return false on a work part of a diptych" do
        expect(works(:work_diptych_1)).not_to be_appraisable
      end
    end
    describe "#artist_#\{index\}_methods" do
      it "should have a first artist" do
        w = works(:work1)
        expect(w.artist_0_last_name).to eq("artist_1")
        expect(w.artist_0_first_name).to eq("firstname")
      end
      it "should return nil when no artist is found at index" do
        w = works(:work1)
        expect(w.artist_4_last_name).to eq(nil)
        expect(w.artist_4_first_name).to eq(nil)
      end
    end
    describe "#frame_type" do
      it "should be able to set a FrameType" do
        w = works(:work1)
        w.frame_type = FrameType.create(name: "test")
        w.save
        expect(w.frame_type.name).to eq("test")
      end
    end
    describe "#stock_number_file_safe" do
      it "should not change good number" do
        expect(Work.new(stock_number: 123).stock_number_file_safe).to eq "123"
      end
      it "should change risky number" do
        expect(Work.new(stock_number: "12/3").stock_number_file_safe).to eq "12-3"
        expect(Work.new(stock_number: "12//3").stock_number_file_safe).to eq "12--3"
        expect(Work.new(stock_number: "1:\\2//3").stock_number_file_safe).to eq "1--2--3"
      end
    end
    describe "#height" do
      it "should accept integer" do
        w = works(:work1)
        w.height = 1
        w.save
        w.reload
        expect(w.height).to eq 1.0
      end
      it "should accept string" do
        w = works(:work1)
        w.height = "12"
        w.save
        w.reload
        expect(w.height).to eq 12.0
      end
      it "should accept us-localized string" do
        w = works(:work1)
        w.height = "12.1"
        w.save
        w.reload
        expect(w.height).to eq 12.1
      end
      it "should accept nl-localized string" do
        w = works(:work1)
        w.height = "12,1"
        w.save
        w.reload
        expect(w.height).to eq 12.1
      end
      it "should accept long nl-localized string" do
        w = works(:work1)
        w.height = "12.012,1"
        w.save
        w.reload
        expect(w.height).to eq 12012.1
      end
    end
    describe "#purchased_on=" do
      it "should accept a date" do
        w = works(:work1)
        date = Date.new(1978, 12, 22)
        w.purchased_on = date
        w.save
        w.reload
        expect(w.purchased_on).to eq(date)
        expect(w.purchase_year).to eq(1978)
      end
      it "should not fail on an empty string" do
        w = works(:work1)
        w.purchased_on = ""
        w.save
        w.reload
        expect(w.purchased_on).to eq(nil)
        expect(w.purchase_year).to eq(nil)
      end
      it "should accept a string" do
        w = works(:work1)
        date = Date.new(1978, 12, 22)
        date_string = date.to_s
        w.purchased_on = date_string
        w.save
        w.reload
        expect(w.purchased_on).to eq(date)
        expect(w.purchase_year).to eq(1978)
      end
      it "should accept a nil" do
        w = works(:work1)
        w.purchased_on = nil
        w.save
        w.reload
        expect(w.purchased_on).to be_nil
      end
      it "should accept a number" do
        w = works(:work1)
        date = 2012
        w.purchased_on = date
        w.save
        w.reload
        expect(w.purchased_on).to eq(nil)
        expect(w.purchase_year).to eq(2012)
      end
      it "should accept a number in a string" do
        w = works(:work1)
        date = "2012"
        w.purchased_on = date
        w.save
        w.reload
        expect(w.purchased_on).to eq(nil)
        expect(w.purchase_year).to eq(2012)
      end
    end
    describe "#damage_types" do
      it "should be an empty by default" do
        w = works(:work2)
        expect(w.damage_types).to eq([])
      end
      it "should should touch work on add (and should only return once)" do
        w = works(:work2)
        original_updated_at = w.updated_at
        w.damage_types << damage_types(:a)
        w.damage_types << damage_types(:a)
        expect(w.damage_types).to match_array([damage_types(:a)])
        expect(w.updated_at - original_updated_at).to be > 0.001
      end
    end
    describe "#cluster_name" do
      it "should set cluster to nil when name is nil or empty" do
        w = works(:work1)
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = ""
        expect(w.cluster).to eq(nil)
        w = works(:work1)
        w.reload
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = nil
        expect(w.cluster).to eq(nil)
        w.save
        w.reload
        w = works(:work1)
        expect(w.cluster).to eq(nil)
      end
      it "should reset cluster when set to a different name" do
        w = works(:work1)
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = "cluster2"
        expect(w.cluster).to eq(clusters(:cluster2))
        w.save
        w.reload
        expect(w.cluster).to eq(clusters(:cluster2))
      end
      it "should create cluster when set to a different name" do
        w = works(:work1)
        expect(w.cluster).to eq(clusters(:cluster1))
        w.cluster_name = "cluster new"
        expect(w.cluster.class).to eq(Cluster)
        w.save
        w.reload
        expect(w.cluster_name).to eq("cluster new")
      end
    end

    describe "#location_description" do
      it "concats the location fields" do
        expect(works(:work1).location_description).to eq("Adres; Floor 1; Room 1")
      end
      it "returns emtpy string when none" do
        expect(Work.new.location_description).to eq(nil)
      end
    end
    describe "#location_history" do
      it "returns an empty array if no history" do
        expect(works(:work1).location_history).to eq([])
      end
      it "returns a single item array if no history" do
        work1 = works(:work1)
        work1.location = "New adress"
        work1.save
        work1.location = "Newer address"
        work1.save
        expect(works(:work1).location_history.collect { |a| a[:location] }).to eq(["New adress", "Newer address"])
      end
      it "returns complete history if work is created after enabling history" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = "second location"
        work.save
        work.location = "third location"
        work.save
        expect(work.location_history.collect { |a| a[:location] }).to eq(["first location", "second location", "third location"])
      end
      it "skip_current options skips current" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = "second location"
        work.save
        expect(work.location_history(skip_current: true).collect { |a| a[:location] }).to eq(["first location"])
      end
      it "returns empty location if empty location" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = nil
        work.save
        expect(work.location_history.collect { |a| a[:location] }).to eq(["first location", nil])
      end
      it "never returns empty location if empty location and no empty locations" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = ""
        work.save
        expect(work.location_history(empty_locations: false).collect { |a| a[:location] }).to eq(["first location"])
      end
      it "never returns empty location if empty location and no empty locations (and doesn't just pop the skip current false)" do
        work = collections(:collection1).works.create(location: "first location")
        work.location = ""
        work.save
        expect(work.location_history(empty_locations: false, skip_current: true).collect { |a| a[:location] }).to eq(["first location"])
      end
    end
    describe "#purchased_on_with_fallback" do
      it "should return nil when not set" do
        w = works(:work1)
        expect(w.purchased_on_with_fallback).to eq(nil)
      end
      it "should return date both year and date are present" do
        w = works(:work1)
        w.purchased_on = Date.new(1978, 12, 22)
        w.purchase_year = 1978
        expect(w.purchased_on_with_fallback).to eq(Date.new(1978, 12, 22))
      end
      it "should return year if only year is present" do
        w = works(:work1)
        w.purchase_year = 1978
        expect(w.purchased_on_with_fallback).to eq(1978)
      end
    end
    describe "#next" do
      it "should redirect to the next work" do
        w = works(:work1)
        expect(w.next).to eq(works(:work2))
        expect(w.next.next).to eq(works(:work5))
      end
      it "should return first if no next" do
        expect(works(:work5).next).to eq(works(:work1))
      end
    end
    describe "#previous" do
      it "should redirect to the previous work" do
        w = works(:work5)
        expect(w.previous).to eq(works(:work2))
        expect(w.previous.previous).to eq(works(:work1))
      end
      it "should return last if no previous" do
        expect(works(:work1).previous).to eq(works(:work5))
      end
    end
    describe "#object_creation_year" do
      it "should return nil if object_creation_year_unknown = true" do
        w = works(:work2)
        w.object_creation_year = 2012
        w.save
        w.reload
        expect(w.object_creation_year).to eq(2012)
        w.object_creation_year_unknown = true
        w.save
        w.reload
        expect(w.object_creation_year).to eq(nil)
      end
    end
    describe "#object_format_code" do
      it "should return proper format code" do
        expect(works(:work2).object_format_code).to eq(nil)
        w = works(:work2)
        w.height = 200
        expect(w.object_format_code).to eq(:xl)
        w.height = 90
        expect(w.object_format_code).to eq(:l)
      end
    end
    describe "#frame_size_with_fallback" do
      it "should return frame size by default" do
        expect(works(:work1).frame_size_with_fallback).to eq(works(:work1).frame_size)
        expect(works(:work2).frame_size_with_fallback).to eq(nil)
        # expect(works(:work2).frame_size_with_fallback).to eq(works(:work2).frame_size)
      end
      it "should return work size if frame size is not present" do
        w = works(:work2)
        w.height = 90
        w.width = 180
        expect(works(:work2).frame_size_with_fallback).not_to eq(nil)
        expect(works(:work2).frame_size_with_fallback).to eq("180 × 90 (b×h)")
      end
    end
    describe "#restore_last_location_if_blank!" do
      it "shoudl restore last location when blenk" do
        w = collections(:collection1).works.create(location: "first location")

        original_location_description = w.location_description
        w.location = nil
        w.location_floor = nil
        w.location_detail = nil
        w.save

        expect(w.location_description).to eq(nil)
        expect(w.versions.last.reify.location_description).to eq(original_location_description)
        w.restore_last_location_if_blank!
        w.reload
        expect(w.location_description).to eq(original_location_description)
      end
      it "should not 'restore' a location if location is set" do
        w = collections(:collection1).works.create(location: "first location")
        w.location = "new location"
        w.save
        w.restore_last_location_if_blank!
        w.reload
        expect(w.location_description).to eq("new location")
      end
    end
    describe "#save" do
      it "should save, even without info" do
        w = collections(:collection1).works.new
        w.save
        expect(w.id).to be > 1
      end
      # it "should save, even with just comments set" do
      #   w = Work.new
      #   w.save
      #   expect(w.id).to be > 1
      # end
    end
    describe "public_tag_list" do
      it "filters public tags" do
        w = Work.create(collection: collections(:collection1), tag_list: %(inventariseren 2020, vermist, 1984, blauw, bekijKen op, aangetroffen, naar fotograaf, selectie, H3 definitief, ontzamelen, aankopen, herplaatsen, navragen, Herplaatsing, Industrie))
        expect(w.public_tag_list).to eq(["1984", "blauw", "Industrie"])
      end
    end
    describe "work_set_attributes=" do
      it "ignores empty hashes" do
        w = Work.create(work_set_attributes: {})
        expect(w.work_sets.count).to eq(0)
      end
      it "ignores partially empty hashes" do
        w = Work.create(work_set_attributes: {identification_number: 123})
        expect(w.work_sets.count).to eq(0)
      end
      it "creates when full hash is given" do
        w = Work.new
        expect {
          w = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect(w.work_sets.count).to eq(1)
      end
      it "reuses when full hash is given equal to earlier in same collection" do
        w1 = Work.new
        w2 = Work.new
        expect {
          w1 = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect {
          w2 = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(0)
        expect(w1.work_sets.count).to eq(1)
        expect(w2.work_sets.count).to eq(1)
        w2.work_sets.reload
        expect(w2.work_sets.first.work_ids).to match_array([w1, w2].map(&:id))
      end
      it "creates when full hash is given equal to earlier in other collection" do
        w1 = Work.new
        w2 = Work.new
        expect {
          w1 = Work.create(collection: collections(:collection1), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect {
          w2 = Work.create(collection: collections(:collection2), work_set_attributes: {work_set_type_id: work_set_types(:meerluik).id, identification_number: 123})
        }.to change(WorkSet, :count).by(1)
        expect(w1.work_sets.count).to eq(1)
        expect(w2.work_sets.count).to eq(1)

        w1.work_sets.reload
        w2.work_sets.reload

        expect(w1.work_sets.first.work_ids).not_to include(w2.id)
        expect(w2.work_sets.first.work_ids).not_to include(w1.id)
      end
    end
  end
  describe "class methods" do
    describe ".artist_name_rendered" do
      it "should not fail on an empty name" do
        w = Work.new
        w.save
        expect(w.artist_name_rendered).to eq(nil)
      end
      it "should summarize the artists nicely" do
        w = works(:work1)
        w.save
        w.reload
        expect(w.artist_name_rendered).to eq("artist_1, firstname (1900 - 2000)")
      end
      it "should respect include_years option" do
        works(:work1).save
        expect(works(:work1).artist_name_rendered(include_years: false)).to eq("artist_1, firstname")
      end
    end
    describe ".artist_name_rendered_without_years_nor_locality" do
      it "should summarize the artist nicely" do
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality).to eq("artist_1, firstname")
      end
      it "should summarize the artists nicely" do
        works(:work1).artists << artists(:artist2)
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_1, firstname")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_2 achternaam, firstie")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match(";")
      end
    end
    describe ".artist_name_rendered_without_years_nor_locality_semicolon_separated" do
      it "should summarize the artist nicely" do
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to eq("artist_1, firstname")
      end
      it "should summarize the artists nicely" do
        works(:work1).artists << artists(:artist2)
        works(:work1).save
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_1, firstname")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match("artist_2 achternaam, firstie")
        expect(works(:work1).artist_name_rendered_without_years_nor_locality_semicolon_separated).to match(";")
      end
    end

    describe ".count_as_whole_works" do
      it "should return all works uniquele" do
        work_count = Work.count
        works_in_worksets_counted_as_one = WorkSet.count_as_one.flat_map { |a| a.works.pluck(:id) }.uniq.count
        worksets_counted_as_one = WorkSet.count_as_one.count

        expect(Work.count_as_whole_works).to eq(work_count - works_in_worksets_counted_as_one + worksets_counted_as_one)
      end

      it "should return all works uniquely even when in two work sets" do
        work_count = Work.count
        works_in_worksets_counted_as_one = WorkSet.count_as_one.flat_map { |a| a.works.pluck(:id) }.uniq.count
        worksets_counted_as_one = WorkSet.count_as_one.count

        WorkSet.create(work_set_type: work_set_types(:possible_same_artist), works: [works(:work_diptych_1), works(:artistless_work)])

        expect(Work.count_as_whole_works).to eq(work_count - works_in_worksets_counted_as_one + worksets_counted_as_one)
      end
    end
    describe ".possible_exposable_fields" do
      it "should return possible_exposable_fields" do
        expect(Work.possible_exposable_fields).to include("owner")
        expect(Work.possible_exposable_fields).to include("location_detail")
        expect(Work.possible_exposable_fields).to include("location_floor")
      end
    end

    describe ".fast_aggregations" do
      it "should allow to be initialized" do
        works(:work1)
        works(:work2)
        aggregations = Work.fast_aggregations [:title, :themes, :subset, :grade_within_collection]
        expect(aggregations.count).to eq 4
        expect(aggregations[:title]["Work1"][:count]).to eq 999999
        expect(aggregations[:themes][themes(:wind)][:count]).to eq 999999
        expect(aggregations[:grade_within_collection]["A"][:count]).to eq 999999
        expect(aggregations[:grade_within_collection]["H"]).to eq nil
      end
    end
    describe ".whd_to_s" do
      it "should render nil if all are nil" do
        expect(Work.new.whd_to_s).to eq(nil)
      end
      it "should render w x h x d if set" do
        expect(Work.new.whd_to_s(1, 2, 3)).to eq("1 × 2 × 3 (b×h×d)")
      end
      it "should round w x h x d" do
        expect(Work.new.whd_to_s(1.002345, 2.2323543, 3.777777)).to eq("1,0023 × 2,2324 × 3,7778 (b×h×d)")
      end
      it "should add diameter if set" do
        expect(Work.new.whd_to_s(1, 2, 3, 4)).to eq("1 × 2 × 3 (b×h×d); ⌀ 4")
      end
      it "should add diameter if set" do
        expect(Work.new.whd_to_s(1, nil, 3, 4)).to eq("1 × 3 (b×d); ⌀ 4")
      end
    end
    describe ".frame_size" do
      it "should use whd_to_s" do
        expect(Work.new(frame_width: 1, frame_height: nil, frame_depth: 3, frame_diameter: 4).frame_size).to eq("1 × 3 (b×d); ⌀ 4")
      end
    end
    describe ".to_workbook" do
      let(:collection) { collections(:collection_with_works) }

      it "should be callable and return a workbook" do
        expect(Work.to_workbook.class).to eq(Workbook::Book)
      end
      it "should be work even with complex fieldset" do
        expect(Work.to_workbook(collection.fields_to_expose(:default)).class).to eq(Workbook::Book)
      end
      it "should work with tags" do
        work = collection.works.first
        work.tag_list = "kaas"
        work.save
        expect(Work.to_workbook(collection.fields_to_expose(:default)).class).to eq(Workbook::Book)
      end
      it "should return basic types" do
        work = collection.works.order(:stock_number).first
        work.save
        workbook = collection.works.order(:stock_number).to_workbook(collection.fields_to_expose(:default))
        expect(workbook.class).to eq(Workbook::Book)
        expect(workbook.sheet.table[1][:inventarisnummer].value).to eq(work.stock_number)
        expect(work.artists.first.name).to eq("artist_1, firstname (1900 - 2000)")
        expect(workbook.sheet.table[1][:vervaardigers].value).to eq("artist_1, firstname")
      end
      it "should allow for sorting by location" do
        workbook = collection.works.order(:location).to_workbook(collection.fields_to_expose(:default))
        expect(workbook.class).to eq(Workbook::Book)
        expect(workbook.sheet.table[1][:vervaardigers].value).to eq("artist_1, firstname")
{'fraction_non_alphanumeric': 0.10589764555422773, 'fraction_numerical': 0.019351321886072498, 'mean_word_length': 2.571546237364283, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '323615', 'n_tokens_mistral': 15744, 'n_tokens_neox': 15117, 'n_words': 3611}