       atom.config.set('foo.bar.baz', "value 10")
       expect(bazCatHandler).not.toHaveBeenCalled()
 
-    describe "observing scoped settings", ->
+    describe "when a 'scope' is given", ->
       otherHandler = null
 
       beforeEach ->


        expect(atom.config.get('foo.bar.baz', scope: ['.source.coffee'])).toBe 10

  describe ".getSources()", ->
    it "returns an array of all of the config's source names", ->
      expect(atom.config.getSources()).toEqual([])

      atom.config.set("a.b", 1, scopeSelector: ".x1", source: "source-1")
      atom.config.set("a.c", 1, scopeSelector: ".x1", source: "source-1")
      atom.config.set("a.b", 2, scopeSelector: ".x2", source: "source-2")
      atom.config.set("a.b", 1, scopeSelector: ".x3", source: "source-3")

      expect(atom.config.getSources()).toEqual([
        "source-1"
        "source-2"
        "source-3"
      ])

  describe ".getSettings()", ->
    it "returns all settings including defaults", ->
      atom.config.setDefaults("foo", bar: baz: 10)
      atom.config.set("foo.ok", 12)

      jasmine.snapshotDeprecations()
      expect(atom.config.getSettings().foo).toEqual
        ok: 12
        bar:
          baz: 10
      jasmine.restoreDeprecationsSnapshot()

  describe ".pushAtKeyPath(keyPath, value)", ->
    it "pushes the given value to the array at the key path and updates observers", ->
      atom.config.set("foo.bar.baz", ["a"])
      observeHandler = jasmine.createSpy "observeHandler"
      atom.config.observe "foo.bar.baz", observeHandler
      observeHandler.reset()

      expect(atom.config.pushAtKeyPath("foo.bar.baz", "b")).toBe 2
      expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
      expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")

  describe ".unshiftAtKeyPath(keyPath, value)", ->
    it "unshifts the given value to the array at the key path and updates observers", ->
      atom.config.set("foo.bar.baz", ["b"])
      observeHandler = jasmine.createSpy "observeHandler"
      atom.config.observe "foo.bar.baz", observeHandler
      observeHandler.reset()

      expect(atom.config.unshiftAtKeyPath("foo.bar.baz", "a")).toBe 2
      expect(atom.config.get("foo.bar.baz")).toEqual ["a", "b"]
      expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")

  describe ".removeAtKeyPath(keyPath, value)", ->
    it "removes the given value from the array at the key path and updates observers", ->
      atom.config.set("foo.bar.baz", ["a", "b", "c"])
      observeHandler = jasmine.createSpy "observeHandler"
      atom.config.observe "foo.bar.baz", observeHandler
      observeHandler.reset()

      expect(atom.config.removeAtKeyPath("foo.bar.baz", "b")).toEqual ["a", "c"]
      expect(atom.config.get("foo.bar.baz")).toEqual ["a", "c"]
      expect(observeHandler).toHaveBeenCalledWith atom.config.get("foo.bar.baz")

  describe ".getPositiveInt(keyPath, defaultValue)", ->
    beforeEach ->
      jasmine.snapshotDeprecations()

    afterEach ->
      jasmine.restoreDeprecationsSnapshot()

    it "returns the proper coerced value", ->
      atom.config.set('editor.preferredLineLength', 0)
      expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1

    it "returns the proper coerced value", ->
      atom.config.set('editor.preferredLineLength', -1234)
      expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 1

    it "returns the default value when a string is passed in", ->
      atom.config.set('editor.preferredLineLength', 'abcd')
      expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80

    it "returns the default value when null is passed in", ->
      atom.config.set('editor.preferredLineLength', null)
      expect(atom.config.getPositiveInt('editor.preferredLineLength', 80)).toBe 80

  describe ".save()", ->
    CSON = require 'season'

    beforeEach ->
      spyOn(CSON, 'writeFileSync')
      jasmine.unspy atom.config, 'save'

    describe "when ~/.atom/config.json exists", ->
      it "writes any non-default properties to ~/.atom/config.json", ->
        atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.json")
        atom.config.set("a.b.c", 1)
        atom.config.set("a.b.d", 2)
        atom.config.set("x.y.z", 3)
        atom.config.setDefaults("a.b", e: 4, f: 5)

        CSON.writeFileSync.reset()
        atom.config.save()

        expect(CSON.writeFileSync.argsForCall[0][0]).toBe path.join(atom.config.configDirPath, "atom.config.json")
        writtenConfig = CSON.writeFileSync.argsForCall[0][1]
        expect(writtenConfig).toEqual global: atom.config.settings

    describe "when ~/.atom/config.json doesn't exist", ->
      it "writes any non-default properties to ~/.atom/config.cson", ->
        atom.config.configFilePath = path.join(atom.config.configDirPath, "atom.config.cson")
        atom.config.set("a.b.c", 1)
        atom.config.set("a.b.d", 2)
        atom.config.set("x.y.z", 3)
        atom.config.setDefaults("a.b", e: 4, f: 5)

        CSON.writeFileSync.reset()
        atom.config.save()

        expect(CSON.writeFileSync.argsForCall[0][0]).toBe path.join(atom.config.configDirPath, "atom.config.cson")
        writtenConfig = CSON.writeFileSync.argsForCall[0][1]
        expect(writtenConfig).toEqual global: atom.config.settings

    describe "when scoped settings are defined", ->
      it 'writes out explicitly set config settings', ->
        atom.config.set('foo.bar', 'ruby', scopeSelector: '.source.ruby')
        atom.config.set('foo.omg', 'wow', scopeSelector: '.source.ruby')
        atom.config.set('foo.bar', 'coffee', scopeSelector: '.source.coffee')

        CSON.writeFileSync.reset()
        atom.config.save()

        writtenConfig = CSON.writeFileSync.argsForCall[0][1]
        expect(writtenConfig).toEqualJson
          global:
            atom.config.settings
          '.ruby.source':
            foo:
              bar: 'ruby'
              omg: 'wow'
          '.coffee.source':
            foo:
              bar: 'coffee'

  describe ".setDefaults(keyPath, defaults)", ->
    it "assigns any previously-unassigned keys to the object at the key path", ->
      atom.config.set("foo.bar.baz", a: 1)
      atom.config.setDefaults("foo.bar.baz", a: 2, b: 3, c: 4)
      expect(atom.config.get("foo.bar.baz.a")).toBe 1
      expect(atom.config.get("foo.bar.baz.b")).toBe 3
      expect(atom.config.get("foo.bar.baz.c")).toBe 4

      atom.config.setDefaults("foo.quux", x: 0, y: 1)
      expect(atom.config.get("foo.quux.x")).toBe 0
      expect(atom.config.get("foo.quux.y")).toBe 1

    it "emits an updated event", ->
      updatedCallback = jasmine.createSpy('updated')
      atom.config.onDidChange('foo.bar.baz.a', updatedCallback)
      expect(updatedCallback.callCount).toBe 0
      atom.config.setDefaults("foo.bar.baz", a: 2)
      expect(updatedCallback.callCount).toBe 1

  describe ".onDidChange(keyPath)", ->
    [observeHandler, observeSubscription] = []

    describe 'when a keyPath is specified', ->

        expect(atom.config.get("x.y", excludeSources: ["b", "c", "a", atom.config.getUserConfigPath()], scope: [".foo"])).toBe 4
        expect(atom.config.get("x.y", excludeSources: [atom.config.getUserConfigPath()])).toBe 4

    describe "when a 'scope' option is given", ->
      it "returns the property with the most specific scope selector", ->
        atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double.coffee", foo: bar: baz: 42)
        atom.config.addScopedSettings("config", ".source .string.quoted.double", foo: bar: baz: 22)
        atom.config.addScopedSettings("config", ".source", foo: bar: baz: 11)

        expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.double.coffee"])).toBe 42
        expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".string.quoted.double.js"])).toBe 22
        expect(atom.config.get("foo.bar.baz", scope: [".source.js", ".variable.assignment.js"])).toBe 11
        expect(atom.config.get("foo.bar.baz", scope: [".text"])).toBeUndefined()

      it "favors the most recently added properties in the event of a specificity tie", ->
        atom.config.addScopedSettings("config", ".source.coffee .string.quoted.single", foo: bar: baz: 42)
        atom.config.addScopedSettings("config", ".source.coffee .string.quoted.double", foo: bar: baz: 22)

        expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.single"])).toBe 42
        expect(atom.config.get("foo.bar.baz", scope: [".source.coffee", ".string.quoted.single.double"])).toBe 22

      describe 'when there are global defaults', ->
        it 'falls back to the global when there is no scoped property specified', ->
          atom.config.setDefaults("foo", hasDefault: 'ok')
          expect(atom.config.get("foo.hasDefault", scope: [".source.coffee", ".string.quoted.single"])).toBe 'ok'

      describe 'when package settings are added after user settings', ->
        it "returns the user's setting because the user's setting has higher priority", ->
          atom.config.set("foo.bar.baz", 100, scopeSelector: ".source.coffee")
          atom.config.addScopedSettings("some-package", ".source.coffee", foo: bar: baz: 1)
          expect(atom.config.get("foo.bar.baz", scope: [".source.coffee"])).toBe 100

  describe ".set(keyPath, value, {source, scopeSelector})", ->
    it "allows a key path's value to be written", ->
      expect(atom.config.set("foo.bar.baz", 42)).toBe true
      expect(atom.config.get("foo.bar.baz")).toBe 42
