<commit_before>/*jshint asi:true */
"use strict";

describe("README: Tests for browsers without Storage support", function(){

    it("should test that localStorage is enabled in this browser, if it is, this will pass and the remaining tests will be skipped.", function() {

        var msg = [
            "This test is intended to fail to make you aware that",
            "localStorage isn't supported by your browser. While the cache",
            "wont be able to work, its safe to use as it will fail silently.",
            "It will be like always getting a cache miss. Most of the tests",
            "are skipped, but some will run to verify graceful degrading."
        ].join(" ")

        expect(locache.supportsLocalStorage).toBe(true)

    })

    // Tests specific to browsers that don't have local storage. These simply
    // test that the functionality degrades well. All cache attempts will be
    // dropped siliently and fetches should act like a cache miss.
    if(!locache.supportsLocalStorage){

        it("silent failing when localStorage isn't supported", function(){

            locache.set("my_key", "my_value")
            expect(locache.get("my_key")).toBe(null)
            locache.remove("my_key")
            locache.incr("my_key")
            locache.decr("my_key")
            locache.setMany({
                "key 1": "value 1",
                "key 2": "value 2"
            })
            expect(locache.getMany(['key 1', 'key 2'])).toEqual([null, null])
            locache.removeMany(['key 1', 'key 2'])
            locache.flush()
            locache.cleanup()

        })

        it("with no localStorage length and flush", function(){

            expect(locache.length()).toBe(0)
            locache.set("key", "value")
            expect(locache.length()).toBe(0)
            locache.flush()
            expect(locache.length()).toBe(0)

        })

        it("with no localStorage setting, getting and removing simple values", function(){

            var key = "my_key"
            var value = "my_value"

            locache.set(key, value)
            expect(locache.get(key)).toBe(null)

            locache.remove(key)
            expect(locache.get(key)).toBe(null)

        })

        it("with no localStorage setting a value with an expire time", function(){

            var key = "will_expire"
            var value = "value"

            locache.set(key, value, 1)
            expect(locache.get(key)).toBe(null)

        })

        it("with no localStorage incr and decr'ing of keys", function(){

            locache.incr("counter")
            expect(locache.get("counter")).toBe(null)
            locache.decr("counter")
            expect(locache.get("counter")).toBe(null)

        })

        it("with no localStorage test many operations - set, get, remove", function(){

            locache.setMany({
                'key1': 'val1',
                'key2': 'val2',
                'key3': 'val3'
            })

            var vals = locache.getMany(['key1','key2','key3'])
            expect(vals).toEqual([null, null, null])
            locache.removeMany(['key1','key2','key3'])
            var vals2 = locache.getMany(['key1','key2','key3'])
            expect(vals2).toEqual([null, null, null])

        })

        return

    }

})

describe("Tests for browsers with localStorage support", function(){

    if (!locache.supportsLocalStorage) return

    beforeEach(function(){
        window.localStorage.clear()
    })

    /*
     * Resume normal testing - for browsers that *do* support localStorage.
     */

    it("should test the length of the cache and flushing", function(){

        expect(locache.length()).toBe(0)
        locache.set("key", "value")
        expect(locache.length()).toBe(1)
        locache.flush()
        expect(locache.length()).toBe(0)

    })

    it("should test setting, getting and removing simple values", function(){

        var key = "my_key"
        var value = "my_value"

        locache.set(key, value)
        expect(locache.get(key)).toBe(value)

        locache.remove(key)
        expect(locache.get(key)).toBe(null)

        locache.set("my_number", 11)
        expect(locache.get("my_number")).toBe(11)

    })

    it("should test setting a value with an expire time", function(){

        var key = "will_expire"
        var value = "value"

        locache.set(key, value, 1)
        expect(locache.get(key)).toBe(value)

        var callCount = 0

        // Should still be there after 100 ms
        setTimeout(function(){
            expect(locache.get(key)).toBe(value)
            callCount++
        }, 100)

        // after a full second, it should have expired.
        setTimeout(function(){
            expect(locache.get(key)).toBe(null)
            callCount++
        }, 1000)

        waitsFor(function(){
            return callCount == 2
        })

    })

    it("should test incr and decr'ing of keys", function(){

        locache.incr("counter")
        expect(locache.get("counter")).toBe(1)
        locache.incr("counter")
        expect(locache.get("counter")).toBe(2)
        locache.decr("counter")
        expect(locache.get("counter")).toBe(1)
        locache.decr("counter")
        expect(locache.get("counter")).toBe(0)
        locache.decr("counter")
        expect(locache.get("counter")).toBe(-1)

        locache.decr("negativecounter")
        expect(locache.get("negativecounter")).toBe(-1)

        locache.set("my_number", 11)
        locache.incr("my_number")
        expect(locache.get("my_number")).toBe(12)

    })

    it("should test test many operations - set, get, remove", function(){

        locache.setMany({
            'key1': 'val1',
            'key2': 'val2',
            'key3': 'val3'
        })

        var vals = locache.getMany(['key1','key2','key3'])
        expect(vals).toEqual(['val1', 'val2', 'val3'])

        expect(locache.get('key1')).toBe('val1')

        locache.removeMany(['key1','key2','key3'])
        var vals2 = locache.getMany(['key1','key2','key3'])
        expect(vals2).toEqual([null, null, null])

    })

    it("should test storing objects", function(){

        locache.set('user', {
            'name': "Dougal Matthews",
            'admin': true
        })

        var result = locache.get('user')

        expect(result).toEqual({
            'name': "Dougal Matthews",
            'admin': true
        })

    })

    it("should test expire calculations", function(){

        var now = new Date().getTime(),
            past = now / 10,
            future = now * 10

        var key =  "mykey",
            cacheKey = locache.cachePrefix + key,
            expireKey = locache.expirePrefix + key

        // Bypass the normal setting mechanisims by manually calling the
        // storage wrapper around localStorage.
        locache.storage.set(cacheKey, "value")

        // Now manually set the expire date as in the past.
        locache.storage.set(expireKey, past)
        expect(locache.hasExpired(key)).toBe(true)

        // set the expire to "now", plus 5 seconds to make sure its not quite
        // expired yet.
        locache.storage.set(expireKey, now + 5)
        expect(locache.hasExpired(key)).toBe(false)

        // set the expire to "now", minus a second to make sure its just
        // expired.
        locache.storage.set(expireKey, now - 1)
        expect(locache.hasExpired(key)).toBe(true)

        // Finally, test the future.
        locache.storage.set(expireKey, future)
        expect(locache.hasExpired(key)).toBe(false)

    })

    it("should test cleaning up expired values", function(){

        window.localStorage.clear()

        var now = new Date().getTime(),
            past = now / 10,
            future = now * 10

        var key1 =  "mykey1",
            cacheKey1 = locache.cachePrefix + key1,
            expireKey1 = locache.expirePrefix + key1,
            key2 =  "mykey2",
            cacheKey2 = locache.cachePrefix + key2,
            expireKey2 = locache.expirePrefix + key2

        // Bypass the normal setting mechanisims by manually calling the
        // storage wrapper around localStorage.
        locache.storage.set(cacheKey1, "value1")
        locache.storage.set(cacheKey2, "value2")

        // set the first value to expire on a date in the past, and then
        // second to expire in the future.
        locache.storage.set(expireKey1, past)
        locache.storage.set(expireKey2, future)

        // Both values should be stored in localStorage - by passing the
        // normal get method to avoid the checks for validation
        expect(locache.storage.get(cacheKey1)).toBe("value1")
        expect(locache.storage.get(cacheKey2)).toBe("value2")

        // Perform a cleanup.
        locache.cleanup()

        // Check the values again, the first should have been removed but the
        // second should be as originally stored.
        expect(locache.storage.get(cacheKey1)).toBe(null)
        expect(locache.storage.get(cacheKey2)).toBe("value2")

    })

})

describe("Tests for sessionStorage support", function(){

    if (!locache.supportsSessionStorage) return

    beforeEach(function(){
        window.sessionStorage.clear()
    })

    /*
     * Resume normal testing - for browsers that *do* support sessionStorage.
     */

    it("should test setting a value with an expire time", function(){

        var key = "will_expire"
        var value = "value"

        locache.session.set(key, value, 1)
        expect(locache.session.get(key)).toBe(value)

        var callCount = 0

        // Should still be there after 100 ms
        setTimeout(function(){
            expect(locache.session.get(key)).toBe(value)
            callCount++
        }, 100)

        // after a full second, it should have expired.
        setTimeout(function(){
            expect(locache.session.get(key)).toBe(null)
            callCount++
        }, 2000)

        waitsFor(function(){
            return callCount == 2
        })

    })

});

describe("Test for custom storage", function(){

    var f = function(){}
    var mockStorage = {
        set: f,
        enabled: function(){
            return true
        }
    }

    var getSpy = sinon.spy(mockStorage, "set");
    var myCache = locache.createCache({storage: mockStorage})

    myCache.set("x", "y")
    expect(mockStorage.set.calledOnce).toBe(true);

});<commit_msg>UnitTests for custom storage objects<commit_after>/*jshint asi:true */
"use strict";

describe("README: Tests for browsers without Storage support", function(){

    it("should test that localStorage is enabled in this browser, if it is, this will pass and the remaining tests will be skipped.", function() {

        var msg = [
            "This test is intended to fail to make you aware that",
            "localStorage isn't supported by your browser. While the cache",
            "wont be able to work, its safe to use as it will fail silently.",
            "It will be like always getting a cache miss. Most of the tests",
            "are skipped, but some will run to verify graceful degrading."
        ].join(" ")

        expect(locache.supportsLocalStorage).toBe(true)

    })

    // Tests specific to browsers that don't have local storage. These simply
    // test that the functionality degrades well. All cache attempts will be
    // dropped siliently and fetches should act like a cache miss.
    if(!locache.supportsLocalStorage){

        it("silent failing when localStorage isn't supported", function(){

            locache.set("my_key", "my_value")
            expect(locache.get("my_key")).toBe(null)
            locache.remove("my_key")
            locache.incr("my_key")
            locache.decr("my_key")
            locache.setMany({
                "key 1": "value 1",
                "key 2": "value 2"
            })
            expect(locache.getMany(['key 1', 'key 2'])).toEqual([null, null])
            locache.removeMany(['key 1', 'key 2'])
            locache.flush()
            locache.cleanup()

        })

        it("with no localStorage length and flush", function(){

            expect(locache.length()).toBe(0)
            locache.set("key", "value")
            expect(locache.length()).toBe(0)
            locache.flush()
            expect(locache.length()).toBe(0)

        })

        it("with no localStorage setting, getting and removing simple values", function(){

            var key = "my_key"
            var value = "my_value"

            locache.set(key, value)
            expect(locache.get(key)).toBe(null)

            locache.remove(key)
            expect(locache.get(key)).toBe(null)

        })

        it("with no localStorage setting a value with an expire time", function(){

            var key = "will_expire"
            var value = "value"

            locache.set(key, value, 1)
            expect(locache.get(key)).toBe(null)

        })

        it("with no localStorage incr and decr'ing of keys", function(){

            locache.incr("counter")
            expect(locache.get("counter")).toBe(null)
            locache.decr("counter")
            expect(locache.get("counter")).toBe(null)

        })

        it("with no localStorage test many operations - set, get, remove", function(){

            locache.setMany({
                'key1': 'val1',
                'key2': 'val2',
                'key3': 'val3'
            })

            var vals = locache.getMany(['key1','key2','key3'])
            expect(vals).toEqual([null, null, null])
            locache.removeMany(['key1','key2','key3'])
            var vals2 = locache.getMany(['key1','key2','key3'])
            expect(vals2).toEqual([null, null, null])

        })

        return

    }

})

describe("Tests for browsers with localStorage support", function(){

    if (!locache.supportsLocalStorage) return

    beforeEach(function(){
        window.localStorage.clear()
    })

    /*
     * Resume normal testing - for browsers that *do* support localStorage.
     */

    it("should test the length of the cache and flushing", function(){

        expect(locache.length()).toBe(0)
        locache.set("key", "value")
        expect(locache.length()).toBe(1)
        locache.flush()
        expect(locache.length()).toBe(0)

    })

    it("should test setting, getting and removing simple values", function(){

        var key = "my_key"
        var value = "my_value"

        locache.set(key, value)
        expect(locache.get(key)).toBe(value)

        locache.remove(key)
        expect(locache.get(key)).toBe(null)

        locache.set("my_number", 11)
        expect(locache.get("my_number")).toBe(11)

    })

    it("should test setting a value with an expire time", function(){

        var key = "will_expire"
        var value = "value"

        locache.set(key, value, 1)
        expect(locache.get(key)).toBe(value)

        var callCount = 0

        // Should still be there after 100 ms
        setTimeout(function(){
            expect(locache.get(key)).toBe(value)
            callCount++
        }, 100)

        // after a full second, it should have expired.
        setTimeout(function(){
            expect(locache.get(key)).toBe(null)
            callCount++
        }, 1000)

        waitsFor(function(){
            return callCount == 2
        })

    })

    it("should test incr and decr'ing of keys", function(){

        locache.incr("counter")
        expect(locache.get("counter")).toBe(1)
        locache.incr("counter")
        expect(locache.get("counter")).toBe(2)
        locache.decr("counter")
        expect(locache.get("counter")).toBe(1)
        locache.decr("counter")
        expect(locache.get("counter")).toBe(0)
        locache.decr("counter")
        expect(locache.get("counter")).toBe(-1)

        locache.decr("negativecounter")
        expect(locache.get("negativecounter")).toBe(-1)

        locache.set("my_number", 11)
        locache.incr("my_number")
        expect(locache.get("my_number")).toBe(12)

    })

    it("should test test many operations - set, get, remove", function(){

        locache.setMany({
            'key1': 'val1',
            'key2': 'val2',
            'key3': 'val3'
        })

        var vals = locache.getMany(['key1','key2','key3'])
        expect(vals).toEqual(['val1', 'val2', 'val3'])

        expect(locache.get('key1')).toBe('val1')

        locache.removeMany(['key1','key2','key3'])
        var vals2 = locache.getMany(['key1','key2','key3'])
        expect(vals2).toEqual([null, null, null])

    })

    it("should test storing objects", function(){

        locache.set('user', {
            'name': "Dougal Matthews",
            'admin': true
        })

        var result = locache.get('user')

        expect(result).toEqual({
            'name': "Dougal Matthews",
            'admin': true
        })

    })

    it("should test expire calculations", function(){

        var now = new Date().getTime(),
            past = now / 10,
            future = now * 10

        var key =  "mykey",
            cacheKey = locache.cachePrefix + key,
            expireKey = locache.expirePrefix + key

        // Bypass the normal setting mechanisims by manually calling the
        // storage wrapper around localStorage.
        locache.storage.set(cacheKey, "value")

        // Now manually set the expire date as in the past.
        locache.storage.set(expireKey, past)
        expect(locache.hasExpired(key)).toBe(true)

        // set the expire to "now", plus 5 seconds to make sure its not quite
        // expired yet.
        locache.storage.set(expireKey, now + 5)
        expect(locache.hasExpired(key)).toBe(false)

        // set the expire to "now", minus a second to make sure its just
        // expired.
        locache.storage.set(expireKey, now - 1)
        expect(locache.hasExpired(key)).toBe(true)

        // Finally, test the future.
        locache.storage.set(expireKey, future)
        expect(locache.hasExpired(key)).toBe(false)

    })

    it("should test cleaning up expired values", function(){

        window.localStorage.clear()

        var now = new Date().getTime(),
            past = now / 10,
            future = now * 10

        var key1 =  "mykey1",
            cacheKey1 = locache.cachePrefix + key1,
            expireKey1 = locache.expirePrefix + key1,
            key2 =  "mykey2",
            cacheKey2 = locache.cachePrefix + key2,
            expireKey2 = locache.expirePrefix + key2

        // Bypass the normal setting mechanisims by manually calling the
        // storage wrapper around localStorage.
        locache.storage.set(cacheKey1, "value1")
        locache.storage.set(cacheKey2, "value2")

        // set the first value to expire on a date in the past, and then
        // second to expire in the future.
        locache.storage.set(expireKey1, past)
        locache.storage.set(expireKey2, future)

        // Both values should be stored in localStorage - by passing the
        // normal get method to avoid the checks for validation
        expect(locache.storage.get(cacheKey1)).toBe("value1")
        expect(locache.storage.get(cacheKey2)).toBe("value2")

        // Perform a cleanup.
        locache.cleanup()

        // Check the values again, the first should have been removed but the
        // second should be as originally stored.
        expect(locache.storage.get(cacheKey1)).toBe(null)
        expect(locache.storage.get(cacheKey2)).toBe("value2")

    })

})

describe("Tests for sessionStorage support", function(){

    if (!locache.supportsSessionStorage) return

    beforeEach(function(){
        window.sessionStorage.clear()
    })

    /*
     * Resume normal testing - for browsers that *do* support sessionStorage.
     */

    it("should test setting a value with an expire time", function(){

        var key = "will_expire"
        var value = "value"

        locache.session.set(key, value, 1)
        expect(locache.session.get(key)).toBe(value)

        var callCount = 0

        // Should still be there after 100 ms
        setTimeout(function(){
            expect(locache.session.get(key)).toBe(value)
            callCount++
        }, 100)

        // after a full second, it should have expired.
        setTimeout(function(){
            expect(locache.session.get(key)).toBe(null)
            callCount++
        }, 2000)

        waitsFor(function(){
            return callCount == 2
        })

    })

})

describe("Test for custom storage", function(){

    beforeEach(function(){
        // Define the storage API with no-op functions for stubbing below.
        // Only enabled returns True, as otherwise its backend is never
        // touched (for disabling when browsers don't support a feature, like
        // localStorage).
        var f = function(){}
        this.storage = { set: f, get: f, remove: f, length: f, key: f,
            enabled: function(){ return true}}

        // Create a cache object to re-use, let it create with the default storage
        // and then we will augment it with the mock in each test.
        this.cache = locache.createCache({storage: this.storage})

    })

    it("should call 'set' on the storage object once when an expire isn't provided", function(){
        var spy = sinon.spy(this.storage, 'set')
        this.cache.set("foo", "bar")
        expect(spy.calledOnce).toBe(true)
    })

    it("should call 'set' on the storage object twice when an expire is provided", function(){
        // When setting with an expire value, we need to set the expire key
        // along with the value key. Thus, two calls to storage.set will be
        // made.
        var spy = sinon.spy(this.storage, 'set')
        this.cache.set("foo", "bar", 60)
        expect(spy.calledTwice).toBe(true)
    })

    it("shouldn't call 'set' when the key is falsy", function(){
        var spy = sinon.spy(this.storage, 'set')
        this.cache.get('', 'value', 50)
        expect(spy.callCount).toBe(0)
    })

    it("should call 'get' twice when fetching a key", function(){
        // When getting an object, a lookup to the expire key is also made.
        var spy = sinon.spy(this.storage, 'get')
        this.cache.get("foo")
        expect(spy.calledTwice).toBe(true)
    })

    it("shouldn't call 'get' when the key is falsy", function(){
        // When getting an object, a falsy key, or no key shouldn't do
        // anything
        var spy = sinon.spy(this.storage, 'get')
        this.cache.get()
        expect(spy.callCount).toBe(0)
    })

    it("shouldn't call any functions if the storage is disabled", function(){

        // Stub the storage object to make enabled return false.
        sinon.stub(this.storage, 'enabled').returns(false);

        var spy = sinon.spy(this.storage, 'set')
        this.cache.get('foo', 'bar', 50)
        // Since enabled is false, the set call shouldn't be passed to the
        // storage backend, and thus set wont be called.
        expect(spy.callCount).toBe(0)

    })

})<|endoftext|>


<commit_before>var test = require('../utils').test
import { RuleTester } from 'eslint'

var ruleTester = new RuleTester({ env: { es6: true }})
  , rule = require('../../../lib/rules/namespace')

function error(name, namespace) {
  return { message: `'${name}' not found in imported namespace '${namespace}'.` }
}

ruleTester.run('namespace', rule, {
  valid: [
    test({ code: "import * as foo from './empty-folder';"}),
    test({ code: 'import * as names from "./named-exports"; ' +
                 'console.log((names.b).c); ' }),

    test({ code: 'import * as names from "./named-exports"; ' +
                 'console.log(names.a);' }),
    test({ code: 'import * as names from "./re-export-names"; ' +
                 'console.log(names.foo);' }),
    test({ code: "import * as elements from './jsx';"
         , settings: { 'import/parse-options': { plugins: ['jsx'] }}}),
    test({ code: "import * as foo from './common';"
         , settings: { 'import/ignore': ['common'] } }),

    // destructuring namespaces
    test({ code: 'import * as names from "./named-exports";' +
                 'const { a } = names' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { d: c } = names' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c } = foo\n' +
                 '    , { length } = "names"\n' +
                 '    , alt = names' }),
    // deep destructuring only cares about top level
    test({ code: 'import * as names from "./named-exports";' +
                 'const { ExportedClass: { length } } = names' }),

    // detect scope redefinition
    test({ code: 'import * as names from "./named-exports";' +
                 'function b(names) { const { c } = names }' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'function b() { let names = null; const { c } = names }' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const x = function names() { const { c } = names }' }),

    /////////
    // es7 //
    /////////
    test({ code: 'export * as names from "./named-exports"'
         , parser: 'babel-eslint' }),
    test({ code: 'export defport, * as names from "./named-exports"'
         , parser: 'babel-eslint' }),
    // non-existent is handled by no-unresolved
    test({ code: 'export * as names from "./does-not-exist"'
         , parser: 'babel-eslint' }),

    ///////////////////////
    // deep dereferences //
    ///////////////////////

    test({ code: 'import * as a from "./deep/a"; console.log(a.b.c.d.e)' }),
    test({ code: 'import * as a from "./deep/a"; var {b:{c:{d:{e}}}} = a' }),
  ],

  invalid: [
    test({code: "import * as foo from './common';",
          errors: ["No exported names found in module './common'."]}),
    test({code: "import * as names from './default-export';",
          errors: ["No exported names found in module './default-export'."]}),

    test({ code: "import * as names from './named-exports'; " +
                 ' console.log(names.c);'
         , errors: [error('c', 'names')] }),

    test({ code: "import * as names from './named-exports';" +
                 " console.log(names['a']);"
         , errors: 1 }),

    // assignment warning (from no-reassign)
    test({ code: 'import * as foo from \'./bar\'; foo.foo = \'y\';'
         , errors: [{ message: 'Assignment to member of namespace \'foo\'.'}] }),
    test({ code: 'import * as foo from \'./bar\'; foo.x = \'y\';'
         , errors: 2 }),

    // invalid destructuring
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c } = names'
         , errors: [{ type: 'Property' }] }),
    test({ code: 'import * as names from "./named-exports";' +
                 'function b() { const { c } = names }'
         , errors: [{ type: 'Property' }] }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c: d } = names'
         , errors: [{ type: 'Property' }] }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c: { d } } = names'
         , errors: [{ type: 'Property' }] }),

    /////////
    // es7 //
    /////////
    test({ code: 'export * as names from "./default-export"'
         , parser: 'babel-eslint'
         , errors: 1 }),
    test({ code: 'export defport, * as names from "./default-export"'
         , parser: 'babel-eslint'
         , errors: 1 }),

    // parse errors
    test({
      code: "import * as namespace from './malformed.js';",
      errors: [{
        message: "Parse errors in imported module './malformed.js'.",
        type: 'Literal',
      }],
    }),

    ///////////////////////
    // deep dereferences //
    ///////////////////////
    test({
      code: 'import * as a from "./deep/a"; console.log(a.b.e)',
      errors: [ "'e' not found in deeply imported namespace 'a.b'." ],
    }),
    test({
      code: 'import * as a from "./deep/a"; console.log(a.b.c.e)',
      errors: [ "'e' not found in deeply imported namespace 'a.b.c'." ],
    }),
    test({
      code: 'import * as a from "./deep/a"; var {b:{ e }} = a',
      errors: [ "'e' not found in deeply imported namespace 'a.b'." ],
    }),
    test({
      code: 'import * as a from "./deep/a"; var {b:{c:{ e }}} = a',
      errors: [ "'e' not found in deeply imported namespace 'a.b.c'." ],
    }),
  ],
})
<commit_msg>referencing children of children is fine<commit_after>var test = require('../utils').test
import { RuleTester } from 'eslint'

var ruleTester = new RuleTester({ env: { es6: true }})
  , rule = require('../../../lib/rules/namespace')

function error(name, namespace) {
  return { message: `'${name}' not found in imported namespace '${namespace}'.` }
}

ruleTester.run('namespace', rule, {
  valid: [
    test({ code: "import * as foo from './empty-folder';"}),
    test({ code: 'import * as names from "./named-exports"; ' +
                 'console.log((names.b).c); ' }),

    test({ code: 'import * as names from "./named-exports"; ' +
                 'console.log(names.a);' }),
    test({ code: 'import * as names from "./re-export-names"; ' +
                 'console.log(names.foo);' }),
    test({ code: "import * as elements from './jsx';"
         , settings: { 'import/parse-options': { plugins: ['jsx'] }}}),
    test({ code: "import * as foo from './common';"
         , settings: { 'import/ignore': ['common'] } }),

    // destructuring namespaces
    test({ code: 'import * as names from "./named-exports";' +
                 'const { a } = names' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { d: c } = names' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c } = foo\n' +
                 '    , { length } = "names"\n' +
                 '    , alt = names' }),
    // deep destructuring only cares about top level
    test({ code: 'import * as names from "./named-exports";' +
                 'const { ExportedClass: { length } } = names' }),

    // detect scope redefinition
    test({ code: 'import * as names from "./named-exports";' +
                 'function b(names) { const { c } = names }' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'function b() { let names = null; const { c } = names }' }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const x = function names() { const { c } = names }' }),

    /////////
    // es7 //
    /////////
    test({ code: 'export * as names from "./named-exports"'
         , parser: 'babel-eslint' }),
    test({ code: 'export defport, * as names from "./named-exports"'
         , parser: 'babel-eslint' }),
    // non-existent is handled by no-unresolved
    test({ code: 'export * as names from "./does-not-exist"'
         , parser: 'babel-eslint' }),

    ///////////////////////
    // deep dereferences //
    ///////////////////////

    test({ code: 'import * as a from "./deep/a"; console.log(a.b.c.d.e)' }),
    test({ code: 'import * as a from "./deep/a"; console.log(a.b.c.d.e.f)' }),
    test({ code: 'import * as a from "./deep/a"; var {b:{c:{d:{e}}}} = a' }),
  ],

  invalid: [
    test({code: "import * as foo from './common';",
          errors: ["No exported names found in module './common'."]}),
    test({code: "import * as names from './default-export';",
          errors: ["No exported names found in module './default-export'."]}),

    test({ code: "import * as names from './named-exports'; " +
                 ' console.log(names.c);'
         , errors: [error('c', 'names')] }),

    test({ code: "import * as names from './named-exports';" +
                 " console.log(names['a']);"
         , errors: 1 }),

    // assignment warning (from no-reassign)
    test({ code: 'import * as foo from \'./bar\'; foo.foo = \'y\';'
         , errors: [{ message: 'Assignment to member of namespace \'foo\'.'}] }),
    test({ code: 'import * as foo from \'./bar\'; foo.x = \'y\';'
         , errors: 2 }),

    // invalid destructuring
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c } = names'
         , errors: [{ type: 'Property' }] }),
    test({ code: 'import * as names from "./named-exports";' +
                 'function b() { const { c } = names }'
         , errors: [{ type: 'Property' }] }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c: d } = names'
         , errors: [{ type: 'Property' }] }),
    test({ code: 'import * as names from "./named-exports";' +
                 'const { c: { d } } = names'
         , errors: [{ type: 'Property' }] }),

    /////////
    // es7 //
    /////////
    test({ code: 'export * as names from "./default-export"'
         , parser: 'babel-eslint'
         , errors: 1 }),
    test({ code: 'export defport, * as names from "./default-export"'
         , parser: 'babel-eslint'
         , errors: 1 }),

    // parse errors
    test({
      code: "import * as namespace from './malformed.js';",
      errors: [{
        message: "Parse errors in imported module './malformed.js'.",
        type: 'Literal',
      }],
    }),

    ///////////////////////
    // deep dereferences //
    ///////////////////////
    test({
      code: 'import * as a from "./deep/a"; console.log(a.b.e)',
      errors: [ "'e' not found in deeply imported namespace 'a.b'." ],
    }),
    test({
      code: 'import * as a from "./deep/a"; console.log(a.b.c.e)',
      errors: [ "'e' not found in deeply imported namespace 'a.b.c'." ],
    }),
    test({
      code: 'import * as a from "./deep/a"; var {b:{ e }} = a',
      errors: [ "'e' not found in deeply imported namespace 'a.b'." ],
    }),
    test({
      code: 'import * as a from "./deep/a"; var {b:{c:{ e }}} = a',
      errors: [ "'e' not found in deeply imported namespace 'a.b.c'." ],
    }),
  ],
})
<|endoftext|>


<commit_before>var extend = require('../utils/extends.js');
var Widget = require('./widget.js');
var AceEditor = require('./ace-editor.js');
var $ = require('../../core/libs/jquery-2.1.3.min.js');
var fu = require('../utils/file-utils.js');

function TabEditor(gui, id, manager){
    Widget.call(this);
    this._editorCount = 0;
    this._element = $('

');
    this._gui = gui;
    this._files = [];
    this._editors = [];
    this._id = id;
    this._selectedTab = -1;
    this._manager = manager;
    this._focus = false;

    var me = this;
    this._element.on('click', '.nav li a', function() {
        var i = $(this).parent().index();
        me.hideSelectedTab();
        me.selectTab(i);
        return false;
    });

    this._element.on('click', '.nav li a span.glyphicon-remove', function() {
        var i = $(this).parent().parent().index();
        me.closeTab(i);
        return false;
    });
}

extend(Widget, TabEditor, {
    hasFocus: function() {
        return this._focus;
    },
    focus: function(focus) {
        this._focus = focus;
        if (focus) {
            this.selectTab(this._selectedTab);
        }
    },
    openFile: function(name, path) {
        var me = this;
        var element = this._element;

        var openedFiles = element.find(['a[href="', path, '"]'].join(''));
        var manager = this._manager;
        if (openedFiles.length) {
            me.hideSelectedTab();
            var i = openedFiles.parent().index();
            me.selectTab(i);
            manager.focusOn(me);
        } else {
            var gui = this._gui;

            var files = this._files;
            var editors = this._editors;

            var tabEditorId = this._id;

            fu.readFile(path, manager, function (err, data) {
                if (err) throw err;

                me.hideSelectedTab();

                var editorContainer = element.find('.editor-container');
                var tabContainer = element.find('.nav');

                var aceEditor = new AceEditor(gui, me._manager, me, tabEditorId, me._editorCount++, path);
                editorContainer.append(aceEditor.element());
                aceEditor.text(data);
                aceEditor.filename(path);
                aceEditor.build();

                var tab = $('
');
                var a = tab.children('a');
                a.attr('href', path);
                a.prepend(name);
                tabContainer.append(tab);

                editors.push(aceEditor);
                me.selectTab(editors.length - 1);
                files.push(path);
                manager.focusOn(me);
            });
        }
    },
    hideSelectedTab: function() {
        var index = this._selectedTab;
        if (index != -1) {
            var editorContainer = this._element.find('.editor-container');
            var tabContainer = this._element.find('.nav');
            this._editors[index].element().hide();

            tabContainer.find('li').eq(index).removeClass('active');
            this._editors[index].ace().blur();
        }
    },
    selectTab: function(index) {
        if (index != -1) {
            this._selectedTab = index;
            var editorContainer = this._element.find('.editor-container');
            var tabContainer = this._element.find('.nav');

            this._editors[index].element().show();
            tabContainer.find('li').eq(index).addClass('active');

            this._editors[index].ace().focus();
        }
    },
    closeTab: function(index) {
        var me = this;
        var editor = me._editors[index];
        var close = function() {
            if (index == me._selectedTab) {
                me.hideSelectedTab();
            }
            me._files.splice(index, 1);
            me._editors.splice(index, 1);

            var editorContainer = me._element.find('.editor-container');
            var tabContainer = me._element.find('.nav');
            editorContainer.find('.se-ace-editor').eq(index).remove();
            tabContainer.find('li').eq(index).remove();

            if (index == me._selectedTab) {
                if (me._selectedTab == me._editors.length) {
                    me._selectedTab = me._editors.length - 1;
                }

                if (me._selectedTab != -1) {
                    me.selectTab(me._selectedTab);
                }
            } else if (index < me._selectedTab) {
                me._selectedTab--;
            }
        }

        if (editor.hasChanges()) {
            editor.ace().blur();
            this._manager.
                showConfirmModal('File has changes',
                                 'This file has changes. Are you sure you want to close it?',
                                 close,
                                 function() { editor.ace().focus(); });
        } else {
            close();
        }
    },
    markAsChanged: function(editor) {
        var index = this._editors.indexOf(editor);
        var tabContainer = this._element.find('.nav');
        tabContainer.find('li').eq(index).children('a').addClass('changed');
    },
    markAsUnchanged: function(editor) {
        var index = this._editors.indexOf(editor);
        var tabContainer = this._element.find('.nav');
        tabContainer.find('li').eq(index).children('a').removeClass('changed');
    },
    closeCurrentTab: function() {
        var me = this;
        me.closeTab(me._selectedTab);
    },
    nextTab: function() {
        this.hideSelectedTab();
        this._selectedTab++;
        if (this._selectedTab > this._editors.length - 1 ) {
            this._selectedTab = 0;
        }
        this.selectTab(this._selectedTab);
    },
    prevTab: function() {
        this.hideSelectedTab();
        this._selectedTab--;
        if (this._selectedTab < 0) {
            this._selectedTab = this._editors.length - 1;
        }
        this.selectTab(this._selectedTab);
    },
    closeAll: function() {
        while (this._editors.length) {
            this.closeTab(0);
        }
    },
    _saveEditorContent: function(editor) {
        var filePath = editor.filePath();
        var content = editor.content();
        var me = this;
        fu.saveFile(filePath, this._manager, content, function() {
            editor.saved();
            me.markAsUnchanged(editor);
        });
    },
    saveCurrentFile: function() {
        var editor = this._editors[this._selectedTab];
        this._saveEditorContent(editor);
    },
    saveAllFiles: function() {
        for (var i = 0 ; i < this._editors.length ; i++) {
            var editor = this._editors[i];
            this._saveEditorContent(editor);
        }
    },
    _updateEditorsFont: function() {
        this._manager.saveConfigs();
        for (var i = 0 ; i < this._editors.length ; i++) {
            var editor = this._editors[i];
            editor.setFontSize(this._manager.config.editorFontSize);
        }
    },
    zoomIn: function() {
        this._manager.config.editorFontSize++;
        this._updateEditorsFont();
    },
    zoomOut: function() {
        if (this._manager.config.editorFontSize > 1) {
            this._manager.config.editorFontSize--;
            this._updateEditorsFont();
        }
    }
});

TabEditor.prototype.constructor = TabEditor;

module.exports = TabEditor;<commit_msg>bug on font size<commit_after>var extend = require('../utils/extends.js');
var Widget = require('./widget.js');
var AceEditor = require('./ace-editor.js');
var $ = require('../../core/libs/jquery-2.1.3.min.js');
var fu = require('../utils/file-utils.js');

var rk = require('rekuire');
var configurationManager = rk('configuration-manager.js');

function TabEditor(gui, id, manager){
    Widget.call(this);
    this._editorCount = 0;
    this._element = $('

');
    this._gui = gui;
    this._files = [];
    this._editors = [];
    this._id = id;
    this._selectedTab = -1;
    this._manager = manager;
    this._focus = false;

    var me = this;
    this._element.on('click', '.nav li a', function() {
        var i = $(this).parent().index();
        me.hideSelectedTab();
        me.selectTab(i);
        return false;
    });

    this._element.on('click', '.nav li a span.glyphicon-remove', function() {
        var i = $(this).parent().parent().index();
        me.closeTab(i);
        return false;
    });
}

extend(Widget, TabEditor, {
    hasFocus: function() {
        return this._focus;
    },
    focus: function(focus) {
        this._focus = focus;
        if (focus) {
            this.selectTab(this._selectedTab);
        }
    },
    openFile: function(name, path) {
        var me = this;
        var element = this._element;

        var openedFiles = element.find(['a[href="', path, '"]'].join(''));
        var manager = this._manager;
        if (openedFiles.length) {
            me.hideSelectedTab();
            var i = openedFiles.parent().index();
            me.selectTab(i);
            manager.focusOn(me);
        } else {
            var gui = this._gui;

            var files = this._files;
            var editors = this._editors;

            var tabEditorId = this._id;

            fu.readFile(path, manager, function (err, data) {
                if (err) throw err;

                me.hideSelectedTab();

                var editorContainer = element.find('.editor-container');
                var tabContainer = element.find('.nav');

                var aceEditor = new AceEditor(gui, me._manager, me, tabEditorId, me._editorCount++, path);
                editorContainer.append(aceEditor.element());
                aceEditor.text(data);
                aceEditor.filename(path);
                aceEditor.build();

                var tab = $('
');
                var a = tab.children('a');
                a.attr('href', path);
                a.prepend(name);
                tabContainer.append(tab);

                editors.push(aceEditor);
                me.selectTab(editors.length - 1);
                files.push(path);
                manager.focusOn(me);
            });
        }
    },
    hideSelectedTab: function() {
        var index = this._selectedTab;
        if (index != -1) {
            var editorContainer = this._element.find('.editor-container');
            var tabContainer = this._element.find('.nav');
            this._editors[index].element().hide();

            tabContainer.find('li').eq(index).removeClass('active');
            this._editors[index].ace().blur();
        }
    },
    selectTab: function(index) {
        if (index != -1) {
            this._selectedTab = index;
            var editorContainer = this._element.find('.editor-container');
            var tabContainer = this._element.find('.nav');

            this._editors[index].element().show();
            tabContainer.find('li').eq(index).addClass('active');

            this._editors[index].ace().focus();
        }
    },
    closeTab: function(index) {
        var me = this;
        var editor = me._editors[index];
        var close = function() {
            if (index == me._selectedTab) {
                me.hideSelectedTab();
            }
            me._files.splice(index, 1);
            me._editors.splice(index, 1);

            var editorContainer = me._element.find('.editor-container');
            var tabContainer = me._element.find('.nav');
            editorContainer.find('.se-ace-editor').eq(index).remove();
            tabContainer.find('li').eq(index).remove();

            if (index == me._selectedTab) {
                if (me._selectedTab == me._editors.length) {
                    me._selectedTab = me._editors.length - 1;
                }

                if (me._selectedTab != -1) {
                    me.selectTab(me._selectedTab);
                }
            } else if (index < me._selectedTab) {
                me._selectedTab--;
            }
        }

        if (editor.hasChanges()) {
            editor.ace().blur();
            this._manager.
                showConfirmModal('File has changes',
                                 'This file has changes. Are you sure you want to close it?',
                                 close,
                                 function() { editor.ace().focus(); });
        } else {
            close();
        }
    },
    markAsChanged: function(editor) {
        var index = this._editors.indexOf(editor);
        var tabContainer = this._element.find('.nav');
        tabContainer.find('li').eq(index).children('a').addClass('changed');
    },
    markAsUnchanged: function(editor) {
        var index = this._editors.indexOf(editor);
        var tabContainer = this._element.find('.nav');
        tabContainer.find('li').eq(index).children('a').removeClass('changed');
    },
    closeCurrentTab: function() {
        var me = this;
        me.closeTab(me._selectedTab);
    },
    nextTab: function() {
        this.hideSelectedTab();
        this._selectedTab++;
        if (this._selectedTab > this._editors.length - 1 ) {
            this._selectedTab = 0;
        }
        this.selectTab(this._selectedTab);
    },
    prevTab: function() {
        this.hideSelectedTab();
        this._selectedTab--;
        if (this._selectedTab < 0) {
            this._selectedTab = this._editors.length - 1;
        }
        this.selectTab(this._selectedTab);
    },
    closeAll: function() {
        while (this._editors.length) {
            this.closeTab(0);
        }
    },
    _saveEditorContent: function(editor) {
        var filePath = editor.filePath();
        var content = editor.content();
        var me = this;
        fu.saveFile(filePath, this._manager, content, function() {
            editor.saved();
            me.markAsUnchanged(editor);
        });
    },
    saveCurrentFile: function() {
        var editor = this._editors[this._selectedTab];
        this._saveEditorContent(editor);
    },
    saveAllFiles: function() {
        for (var i = 0 ; i < this._editors.length ; i++) {
            var editor = this._editors[i];
            this._saveEditorContent(editor);
        }
    },
    _updateEditorsFont: function() {
        for (var i = 0 ; i < this._editors.length ; i++) {
            var editor = this._editors[i];
            editor.setFontSize(configurationManager.get('editorFontSize'));
        }
    },
    zoomIn: function() {
        var size = configurationManager.get('editorFontSize');
        configurationManager.set('editorFontSize', (size + 1))
        this._updateEditorsFont();
    },
    zoomOut: function() {
        var size = configurationManager.get('editorFontSize');
        if (size > 1) {
            configurationManager.set('editorFontSize', (size - 1))
            this._updateEditorsFont();
        }
    }
});

TabEditor.prototype.constructor = TabEditor;

module.exports = TabEditor;<|endoftext|>


<commit_before>var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));

describe("Stage", function() {
  var RepoUtils = require("../utils/repository_setup");
  var NodeGit = require("../../");
	var test;

  beforeEach(function() {
    test = this;
		var repoDir = "../repos/stagingRepo/";
    var repoPath = path.resolve(__dirname, repoDir);

    return RepoUtils.createRepository(repoPath)
      .then(function(repo) {
        test.repository = repo;
        return repo.openIndex();
      })
      .then(function(index) {
        test.index = index;
      });
  });

  after(function() {
		return fse.remove(test.repository.workdir());
  });

function stagingTest(staging, newFileContent) {
    var fileContent = newFileContent ||
                      "One line of text\n" +
                      "Two lines of text\n"+
                      "Three lines of text\n"+
                      "Four lines of text\n"+
                      "Five lines of text\n"+
                      "Six lines of text\n"+
                      "Seven lines of text\n"+
                      "Eight lines of text\n"+
                      "Nine lines of text\n"+
                      "Ten lines of text\n"+
                      "Eleven lines of text\n"+
                      "Twelve lines of text\n"+
                      "Thirteen lines of text\n"+
                      "Fourteen lines of text\n"+
                      "Fifteen lines of text\n"+
                      "Sixteen lines of text\n"+
                      "Seventeen lines of text\n"+
                      "Eighteen lines of text\n"+
                      "Nineteen lines of text\n"+
                      "Twenty lines of text\n";
    var fileName = "stagedLinesTest.txt";
    var index;
    var stagedFile;
    var workingDirFile;
    var getDiffFunction;
    if (staging) {
      stagedFile = fileContent.replace("Fifteen", "Changed fifteen");
      workingDirFile = stagedFile.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      getDiffFunction = function() {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      };
    }
    else {
      stagedFile = fileContent.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      workingDirFile = stagedFile.replace("Fifteen", "Changed fifteen");

      getDiffFunction = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };
    }

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            workingDirFile);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return getDiffFunction();
    })
    .then(function(fileDiff) {
      return fileDiff.patches();
    })
    .then(function(patches) {
      var pathPatch = patches.filter(function(patch) {
        return patch.newFile().path() === fileName;
      });
      return pathPatch[0].hunks();
    })
    .then(function(pathHunks) {
      var linePromises = [];

      pathHunks.forEach(function(pathHunk) {
        linePromises.push(pathHunk.lines());
      });

      return Promise.all(linePromises);
    })
    .then(function(lines) {
      var linesToStage = [];
      lines.forEach(function(hunkLines) {
        hunkLines.forEach(function(line) {
          if (line.content().toLowerCase().indexOf("fifteen") >= 0){
            linesToStage.push(line);
          }
        });
      });
      return test.repository.stageLines(fileName, linesToStage, !staging);
    })
    .then(function(stageResult) {
      assert.equal(stageResult, 0);
      var pathOid = index.getByPath(fileName).id;
      return test.repository.getBlob(pathOid);
    })
    .then(function(resultFileContents) {
      assert.equal(resultFileContents.toString(), stagedFile);
    });
  }

  it("can stage selected lines", function() {
    return stagingTest(true);
  });
  it("can unstage selected lines", function() {
    return stagingTest(false);
  });

  //This is used to test cases where there are no newline at EOF
  var newlineEofTestFileContent =
                  "One line of text\n" +
                  "Two lines of text\n"+
                  "Three lines of text\n"+
                  "Four lines of text\n"+
                  "Five lines of text\n"+
                  "Six lines of text\n"+
                  "Seven lines of text\n"+
                  "Eight lines of text\n"+
                  "Nine lines of text\n"+
                  "Ten lines of text\n"+
                  "Eleven lines of text\n"+
                  "Twelve lines of text\n"+
                  "Thirteen lines of text\n"+
                  "Fourteen lines of text\n"+
                  "Fifteen lines of text";
  it("can stage last line with no newline at EOF", function() {
    return stagingTest(true, newlineEofTestFileContent);
  });
  it("can unstage last line with no newline at EOF", function() {
    return stagingTest(false, newlineEofTestFileContent);
  });
  it("can stage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(true, newlineEofTestFileContent2);
  });
  it("can unstage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(false, newlineEofTestFileContent2);
  });

  //This is used to test case where the last hunk is staged.
  var lastHunkStagedFileContent =
                "Thirteen lines of text\n"+
                "Fourteen lines of text\n"+
                "Fifteen lines of text\n"+
                "Sixteen lines of text\n"+
                "Shforteenteen lines of text\n";

  it("staging last hunk stages whole file if no filemode changes", function() {
    return stagingTest(true, lastHunkStagedFileContent)
      .then(function() {
        return test.repository.openIndex();
      })
      .then(function(index) {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      })
      .then(function(diff) {
        assert.equal(Object.keys(diff).length, 0);  //Empty diff
        return diff.patches();
      })
      .then(function(patches) {
        //patches will have at least one item if there is something unstaged
        assert.equal(patches.length, 0);
      });
  });

  function compareFilemodes(vsWorkdir, index, fileModeDifference) {
    //Takes diff of head commit vs Workdir (if vsWorkdir is set) or vs Index
    //(if vsWorkdir is unset). Note: there's only one file in the filemode
    //staging tests for which this helper fn was written.
    //index - index to use (vsWorkdir is unset)
    //fileModeDifference - expected (newfilemode) - (oldfilemode)
    return test.repository.getHeadCommit()
      .then(function(commit) {
        return commit.getTree();
      })
      .then(function(tree) {
        if (vsWorkdir) {
          return NodeGit.Diff.treeToWorkdir(test.repository, tree);
        } else {
          return NodeGit.Diff.treeToIndex(test.repository, tree, index);
        }
      })
      .then(function(diff) {
        return diff.getDelta(0);
      })
      .then(function(delta) {
        if (fileModeDifference === 0) {
          if (!delta.oldFile && !delta.newFile) {
            return true;
          } else {
            throw ("File change when no file change expected.");
          }
        } else {
          assert(delta.newFile().mode() - delta.oldFile().mode() ===
            fileModeDifference);
        }
        return true;
      });
  }

  it("can stage filemode changes", function() {
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest.txt";
    var index;

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      //First, create a file, have the same file in both the repo and workdir.
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          //Then, change the permission locally.
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0755 /* new filemode */);
        });
    })
    //Then, diff between head commit and workdir should contain filemode change
    .then(function() {
      return compareFilemodes(true, null, 0111 /* expect +x */)
        .then(function() {
          return test.repository.stageFilemode(fileName, true);
        });
    })
    //Now lets do a commit...
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      index.read(1);
      return index.writeTree();
    })
    .then(function (oid) {
      var signature = NodeGit.Signature.create("Foo bar",
        "foo@bar.com", 123456789, 60);
      return test.repository.createCommit("HEAD", signature, signature,
          "initial commit", oid, []);
      //... alright, we did a commit.
    })
    //Now if we compare HEAD to index, there should be a filemode change
    .then(function() {
      return compareFilemodes(false, index, 0111 /* expect +x */);
    });
  });

  it("can unstage filemode changes", function() {
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest2.txt";
    var index;
    var oldFilemode;
    var diffPromise = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0100755);
        });
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return diffPromise();
    })
    .then(function(fileDiff) {
      return fileDiff.getDelta(0);
    })
    .then(function(delta) {
      oldFilemode = delta.oldFile().mode();
      assert(delta.newFile().mode() - delta.oldFile().mode() ===
        0111);

      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return index.entries();
    })
    .then(function(entries) {
      assert(entries[0].mode == 0100755);
      return test.repository.stageFilemode(fileName, false);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return index.entries();
    })
    .then(function(entries) {
      assert(entries[0].mode == oldFilemode);
    });
  });

});
<commit_msg>Have 'unstaging filemode' test check Index, WorkDir, and head commit<commit_after>var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));

describe("Stage", function() {
  var RepoUtils = require("../utils/repository_setup");
  var NodeGit = require("../../");
	var test;

  beforeEach(function() {
    test = this;
		var repoDir = "../repos/stagingRepo/";
    var repoPath = path.resolve(__dirname, repoDir);

    return RepoUtils.createRepository(repoPath)
      .then(function(repo) {
        test.repository = repo;
        return repo.openIndex();
      })
      .then(function(index) {
        test.index = index;
      });
  });

  after(function() {
		return fse.remove(test.repository.workdir());
  });

function stagingTest(staging, newFileContent) {
    var fileContent = newFileContent ||
                      "One line of text\n" +
                      "Two lines of text\n"+
                      "Three lines of text\n"+
                      "Four lines of text\n"+
                      "Five lines of text\n"+
                      "Six lines of text\n"+
                      "Seven lines of text\n"+
                      "Eight lines of text\n"+
                      "Nine lines of text\n"+
                      "Ten lines of text\n"+
                      "Eleven lines of text\n"+
                      "Twelve lines of text\n"+
                      "Thirteen lines of text\n"+
                      "Fourteen lines of text\n"+
                      "Fifteen lines of text\n"+
                      "Sixteen lines of text\n"+
                      "Seventeen lines of text\n"+
                      "Eighteen lines of text\n"+
                      "Nineteen lines of text\n"+
                      "Twenty lines of text\n";
    var fileName = "stagedLinesTest.txt";
    var index;
    var stagedFile;
    var workingDirFile;
    var getDiffFunction;
    if (staging) {
      stagedFile = fileContent.replace("Fifteen", "Changed fifteen");
      workingDirFile = stagedFile.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      getDiffFunction = function() {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      };
    }
    else {
      stagedFile = fileContent.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      workingDirFile = stagedFile.replace("Fifteen", "Changed fifteen");

      getDiffFunction = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };
    }

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            workingDirFile);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return getDiffFunction();
    })
    .then(function(fileDiff) {
      return fileDiff.patches();
    })
    .then(function(patches) {
      var pathPatch = patches.filter(function(patch) {
        return patch.newFile().path() === fileName;
      });
      return pathPatch[0].hunks();
    })
    .then(function(pathHunks) {
      var linePromises = [];

      pathHunks.forEach(function(pathHunk) {
        linePromises.push(pathHunk.lines());
      });

      return Promise.all(linePromises);
    })
    .then(function(lines) {
      var linesToStage = [];
      lines.forEach(function(hunkLines) {
        hunkLines.forEach(function(line) {
          if (line.content().toLowerCase().indexOf("fifteen") >= 0){
            linesToStage.push(line);
          }
        });
      });
      return test.repository.stageLines(fileName, linesToStage, !staging);
    })
    .then(function(stageResult) {
      assert.equal(stageResult, 0);
      var pathOid = index.getByPath(fileName).id;
      return test.repository.getBlob(pathOid);
    })
    .then(function(resultFileContents) {
      assert.equal(resultFileContents.toString(), stagedFile);
    });
  }

  it("can stage selected lines", function() {
    return stagingTest(true);
  });
  it("can unstage selected lines", function() {
    return stagingTest(false);
  });

  //This is used to test cases where there are no newline at EOF
  var newlineEofTestFileContent =
                  "One line of text\n" +
                  "Two lines of text\n"+
                  "Three lines of text\n"+
                  "Four lines of text\n"+
                  "Five lines of text\n"+
                  "Six lines of text\n"+
                  "Seven lines of text\n"+
                  "Eight lines of text\n"+
                  "Nine lines of text\n"+
                  "Ten lines of text\n"+
                  "Eleven lines of text\n"+
                  "Twelve lines of text\n"+
                  "Thirteen lines of text\n"+
                  "Fourteen lines of text\n"+
                  "Fifteen lines of text";
  it("can stage last line with no newline at EOF", function() {
    return stagingTest(true, newlineEofTestFileContent);
  });
  it("can unstage last line with no newline at EOF", function() {
    return stagingTest(false, newlineEofTestFileContent);
  });
  it("can stage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(true, newlineEofTestFileContent2);
  });
  it("can unstage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(false, newlineEofTestFileContent2);
  });

  //This is used to test case where the last hunk is staged.
  var lastHunkStagedFileContent =
                "Thirteen lines of text\n"+
                "Fourteen lines of text\n"+
                "Fifteen lines of text\n"+
                "Sixteen lines of text\n"+
                "Shforteenteen lines of text\n";

  it("staging last hunk stages whole file if no filemode changes", function() {
    return stagingTest(true, lastHunkStagedFileContent)
      .then(function() {
        return test.repository.openIndex();
      })
      .then(function(index) {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      })
      .then(function(diff) {
        assert.equal(Object.keys(diff).length, 0);  //Empty diff
        return diff.patches();
      })
      .then(function(patches) {
        //patches will have at least one item if there is something unstaged
        assert.equal(patches.length, 0);
      });
  });

  function compareFilemodes(vsWorkdir, index, fileModeDifference) {
    //Takes diff of head commit vs Workdir (if vsWorkdir is set) or vs Index
    //(if vsWorkdir is unset). Note: there's only one file in the filemode
    //staging tests for which this helper fn was written.
    //index - index to use (vsWorkdir is unset)
    //fileModeDifference - expected (newfilemode) - (oldfilemode)
    return test.repository.getHeadCommit()
      .then(function(commit) {
        return commit.getTree();
      })
      .then(function(tree) {
        if (vsWorkdir) {
          return NodeGit.Diff.treeToWorkdir(test.repository, tree);
        } else {
          return NodeGit.Diff.treeToIndex(test.repository, tree, index);
        }
      })
      .then(function(diff) {
        return diff.getDelta(0);
      })
      .then(function(delta) {
        if (fileModeDifference === 0) {
          if (!delta) {
            return true;
          } else {
            throw ("File change when no file change expected.");
          }
        } else {
          assert(delta.newFile().mode() - delta.oldFile().mode() ===
            fileModeDifference);
        }
        return true;
      });
  }

  it("can stage filemode changes", function() {
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest.txt";
    var index;

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      //First, create a file, have the same file in both the repo and workdir.
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          //Then, change the permission locally.
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0755 /* new filemode */);
        });
    })
    //Then, diff between head commit and workdir should contain filemode change
    .then(function() {
      return compareFilemodes(true, null, 0111 /* expect +x */)
        .then(function() {
          return test.repository.stageFilemode(fileName, true);
        });
    })
    //Now lets do a commit...
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      index.read(1);
      return index.writeTree();
    })
    .then(function (oid) {
      var signature = NodeGit.Signature.create("Foo bar",
        "foo@bar.com", 123456789, 60);
      return test.repository.createCommit("HEAD", signature, signature,
          "initial commit", oid, []);
      //... alright, we did a commit.
    })
    //Now if we compare head commit to index, there should be a filemode change
    .then(function() {
      return compareFilemodes(false, index, 0111 /* expect +x */);
    });
  });

  it("can unstage filemode changes", function() {
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest2.txt";
    var index;

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      //First, create a file, have the same file in both the repo and workdir.
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          //Then, change the permission locally.
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0755 /* new filemode */);
        });
    })
    //Then, diff between head commit and workdir should contain filemode change
    .then(function() {
      return compareFilemodes(true, null, 0111 /* expect +x */);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      //Now we stage the whole file...
      index = repoIndex;
      index.addByPath(fileName);
      return index.write();
    })
    .then(function() {
      //We expect the Index to have the filemode changes now.
      return compareFilemodes(false, index, 0111 /* expect +x */)
        .then(function() {
          //...then we attempt to unstage filemode
          return test.repository.stageFilemode(fileName, false /* unstage */);
        });
    })
    //We expect the Index to have no filemode changes, since we unstaged.
    .then(function() {
      return compareFilemodes(false, index, 0 /* expect +x */);
    })
    //We also expect the workdir to now have the filemode change.
    .then(function() {
      return compareFilemodes(true, null, 0111 /* expect +x */);
    });
  });

});
<|endoftext|>


<commit_before>/*
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

(function(window, undefined) {

window['AscFonts'] = window['AscFonts'] || {};
var AscFonts = window['AscFonts'];

var g_native_engine = CreateNativeTextMeasurer();

function CReturnObject()
{
	this.error = 0;
}
CReturnObject.prototype.free = function()
{
};

let g_return_obj = new CReturnObject();
let g_return_obj_count = new CReturnObject();
g_return_obj_count.count = 0;

AscFonts.CopyStreamToMemory = function(data, size)
{
	return data;
};

function CShapeString(size)
{
	this.size = size;
	this.pointer = new Uint8Array(size);
}
CShapeString.prototype.getBuffer = function()
{
	return this.pointer;
};
CShapeString.prototype.free = function()
{
	// GC
};
CShapeString.prototype.set = function(index, value)
{
	this.pointer[index] = value;
};

AscFonts.AllocString = function(size)
{
	return new CShapeString(size);
};

AscFonts.FT_CreateLibrary = function(library)
{
	return g_native_engine["FT_Init"](library);
};
AscFonts.FT_Done_Library = function(face)
{
	if (face)
		g_native_engine.FT_Free(face);
};
AscFonts.FT_Set_TrueType_HintProp = function(library, tt_interpreter)
{
	return g_native_engine["FT_Set_TrueType_HintProp"](library, tt_interpreter);
};

AscFonts.FT_Open_Face = function(library, memory, len, face_index)
{
	return g_native_engine["FT_Open_Face2"](library, memory, face_index);
};
AscFonts.FT_Done_Face = function(face)
{
	if (face)
		g_native_engine["FT_Free"](face);
};
AscFonts.FT_SetCMapForCharCode = function(face, unicode)
{
	return g_native_engine["FT_SetCMapForCharCode"](face, unicode);
};
AscFonts.FT_GetKerningX = function(face, gid1, gid2)
{
	return g_native_engine["FT_GetKerningX"](face, gid1, gid2);
};
AscFonts.FT_GetFaceMaxAdvanceX = function(face)
{
	return g_native_engine["FT_GetFaceMaxAdvanceX"](face);
};
AscFonts.FT_Set_Transform = function(face, xx, yx, xy, yy)
{
	return g_native_engine["FT_Set_Transform"](face, xx, yx, xy, yy);
};
AscFonts.FT_Set_Char_Size = function(face, cw, ch, hres, vres)
{
	return g_native_engine["FT_Set_Char_Size"](face, cw, ch, hres, vres);
};
AscFonts.FT_GetFaceInfo = function(face, reader)
{
	var data = g_native_engine["FT_GetFaceInfo"](face);
	if (!data)
	{
		g_return_obj.error = 1;
		return g_return_obj;
	}

	g_return_obj.error = 0;
	reader.init(data, 0, data.length);
	return g_return_obj;
};

AscFonts.FT_Load_Glyph = function(face, gid, mode)
{
	return g_native_engine["FT_Load_Glyph"](face, gid, mode);
};
AscFonts.FT_SetCMapForCharCode = function(face, unicode)
{
	return g_native_engine["FT_SetCMapForCharCode"](face, unicode);
}
AscFonts.FT_Get_Glyph_Measure_Params = function(face, vector_worker, reader)
{
	var data = g_native_engine["FT_Get_Glyph_Measure_Params"](face, vector_worker ? true : false);
	if (!data)
	{
		g_return_obj_count.error = 1;
		return g_return_obj_count;
	}

	reader.init(new Uint8Array(data, 0, data.length));
	g_return_obj_count.count = reader.readInt();
	g_return_obj_count.error = 0;
	return g_return_obj_count;
};
AscFonts.FT_Get_Glyph_Render_Params = function(face, render_mode, reader)
{
	var data = g_native_engine["FT_Get_Glyph_Render_Params"](face, render_mode);
	if (!data)
	{
		g_return_obj.error = 1;
		return g_return_obj;
	}

	g_return_obj.error = 0;
	reader.init(data, 0, data.length);
	return g_return_obj;
};
AscFonts.FT_Get_Glyph_Render_Buffer = function(face, size)
{
	return g_native_engine["FT_Get_Glyph_Render_Buffer"](face, size);
};

let hb_cache_languages = {};
AscFonts.HB_FontFree = function(font)
{
	if (font)
		g_native_engine["FT_Free"](font);
}
AscFonts.HB_ShapeText = function(fontFile, text, features, script, direction, language, reader)
{
	if (!hb_cache_languages[language])
	{
		hb_cache_languages[language] = g_native_engine["HB_LanguageFromString"]();
	}

	if (!fontFile["GetHBFont"]())
		fontFile["SetHBFont"](g_native_engine["FT_Malloc"](0));

	let data = g_native_engine["HB_ShapeText"](fontFile["GetFace"](), fontFile["GetHBFont"](), text.pointer, features, script, direction, hb_cache_languages[language]);
	if (!data)
	{
		g_return_obj_count.error = 1;
		return g_return_obj_count;
	}

	reader.init(new Uint8Array(data, 0, data.length));
	let len = reader.readUInt();
	let fontPointer = reader.readPointer64(); // just skip

	g_return_obj_count.count = (len - 12) / 26;
	g_return_obj_count.error = 0;
	return g_return_obj_count;
};

AscFonts.onLoadModule();
AscFonts.onLoadModule();

})(window, undefined);
<commit_msg>Refactoring (#2887)<commit_after>/*
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

(function(window, undefined) {

window['AscFonts'] = window['AscFonts'] || {};
var AscFonts = window['AscFonts'];

var g_native_engine = CreateNativeTextMeasurer();

function CReturnObject()
{
	this.error = 0;
}
CReturnObject.prototype.free = function()
{
};

let g_return_obj = new CReturnObject();
let g_return_obj_count = new CReturnObject();
g_return_obj_count.count = 0;

AscFonts.CopyStreamToMemory = function(data, size)
{
	return data;
};

function CShapeString(size)
{
	this.size = size;
	this.pointer = new Uint8Array(size);
}
CShapeString.prototype.getBuffer = function()
{
	return this.pointer;
};
CShapeString.prototype.free = function()
{
	// GC
};
CShapeString.prototype.set = function(index, value)
{
	this.pointer[index] = value;
};

AscFonts.AllocString = function(size)
{
	return new CShapeString(size);
};

AscFonts.FT_CreateLibrary = function(library)
{
	return g_native_engine["FT_Init"](library);
};
AscFonts.FT_Done_Library = function(face)
{
	if (face)
		g_native_engine.FT_Free(face);
};
AscFonts.FT_Set_TrueType_HintProp = function(library, tt_interpreter)
{
	return g_native_engine["FT_Set_TrueType_HintProp"](library, tt_interpreter);
};

AscFonts.FT_Open_Face = function(library, memory, len, face_index)
{
	return g_native_engine["FT_Open_Face2"](library, memory, face_index);
};
AscFonts.FT_Done_Face = function(face)
{
	if (face)
		g_native_engine["FT_Free"](face);
};
AscFonts.FT_SetCMapForCharCode = function(face, unicode)
{
	return g_native_engine["FT_SetCMapForCharCode"](face, unicode);
};
AscFonts.FT_GetKerningX = function(face, gid1, gid2)
{
	return g_native_engine["FT_GetKerningX"](face, gid1, gid2);
};
AscFonts.FT_GetFaceMaxAdvanceX = function(face)
{
	return g_native_engine["FT_GetFaceMaxAdvanceX"](face);
};
AscFonts.FT_Set_Transform = function(face, xx, yx, xy, yy)
{
	return g_native_engine["FT_Set_Transform"](face, xx, yx, xy, yy);
};
AscFonts.FT_Set_Char_Size = function(face, cw, ch, hres, vres)
{
	return g_native_engine["FT_Set_Char_Size"](face, cw, ch, hres, vres);
};
AscFonts.FT_GetFaceInfo = function(face, reader)
{
	var data = g_native_engine["FT_GetFaceInfo"](face);
	if (!data)
	{
		g_return_obj.error = 1;
		return g_return_obj;
	}

	g_return_obj.error = 0;
	reader.init(data, 0, data.length);
	return g_return_obj;
};

AscFonts.FT_Load_Glyph = function(face, gid, mode)
{
	return g_native_engine["FT_Load_Glyph"](face, gid, mode);
};
AscFonts.FT_SetCMapForCharCode = function(face, unicode)
{
	return g_native_engine["FT_SetCMapForCharCode"](face, unicode);
}
AscFonts.FT_Get_Glyph_Measure_Params = function(face, vector_worker, reader)
{
	var data = g_native_engine["FT_Get_Glyph_Measure_Params"](face, vector_worker ? true : false);
	if (!data)
	{
		g_return_obj_count.error = 1;
		return g_return_obj_count;
	}

	reader.init(new Uint8Array(data, 0, data.length));
	g_return_obj_count.count = reader.readInt();
	g_return_obj_count.error = 0;
	return g_return_obj_count;
};
AscFonts.FT_Get_Glyph_Render_Params = function(face, render_mode, reader)
{
	var data = g_native_engine["FT_Get_Glyph_Render_Params"](face, render_mode);
	if (!data)
	{
		g_return_obj.error = 1;
		return g_return_obj;
	}

	g_return_obj.error = 0;
	reader.init(data, 0, data.length);
	return g_return_obj;
};
AscFonts.FT_Get_Glyph_Render_Buffer = function(face, size)
{
	return g_native_engine["FT_Get_Glyph_Render_Buffer"](face, size);
};

let hb_cache_languages = {};
AscFonts.HB_FontFree = function(font)
{
	if (font)
		g_native_engine["FT_Free"](font);
}
AscFonts.HB_ShapeText = function(fontFile, text, features, script, direction, language, reader)
{
	if (!hb_cache_languages[language])
	{
		hb_cache_languages[language] = g_native_engine["HB_LanguageFromString"]();
	}

	if (!fontFile["GetHBFont"]())
		fontFile["SetHBFont"](g_native_engine["HB_FontMalloc"]());

	let data = g_native_engine["HB_ShapeText"](fontFile["GetFace"](), fontFile["GetHBFont"](), text.pointer, features, script, direction, hb_cache_languages[language]);
	if (!data)
	{
		g_return_obj_count.error = 1;
		return g_return_obj_count;
	}

	reader.init(new Uint8Array(data, 0, data.length));
	let len = reader.readUInt();
	let fontPointer = reader.readPointer64(); // just skip

	g_return_obj_count.count = (len - 12) / 26;
	g_return_obj_count.error = 0;
	return g_return_obj_count;
};

AscFonts.onLoadModule();
AscFonts.onLoadModule();

})(window, undefined);
<|endoftext|>


<commit_before>export default {
  template: [
    'config',
    (config) => {
      if (config.design == 'md') {
        return require('./partials/legendmd.html');
      } else {
        return require('./partials/legend.html');
      }
    },
  ],
  controller: [
    '$scope',
    'hs.map.service',
    'hs.legend.service',
    function ($scope, OlMap, service) {
      let map;

      angular.extend($scope, {
        layerDescriptors: [],

        /**
         * Add selected layer to the list of layers in legend (with event listener
         * to display/hide legend item when layer visibility change)
         * @memberof hs.legend.controller
         * @function addLayerToLegends
         * @param {object} layer Layer to add legend for
         */
        addLayerToLegends: function (layer) {
          const descriptor = service.getLayerLegendDescriptor(layer);
          if (descriptor) {
            $scope.layerDescriptors.push(descriptor);
            layer.on('change:visible', layerVisibilityChanged);
          }
        },

        /**
         * Check if there is any visible layer
         * @memberof hs.legend.controller
         * @return {Boolea} Returns true if no layers with legend exist
         * @function noLayerExists
         */
        noLayerExists: function () {
          const visibleLayers = $scope.layerDescriptors.filter(
            (check) => check.visible
          );
          return visibleLayers.length == 0;
        },

        /**
         * Remove selected layer from legend items
         * @memberof hs.legend.controller
         * @function removeLayerFromLegends
         * @param {Ol.layer} layer Layer to remove from legend
         */
        removeLayerFromLegends: function (layer) {
          for (let i = 0; i < $scope.layerDescriptors.length; i++) {
            if ($scope.layerDescriptors[i].lyr == layer) {
              $scope.layerDescriptors.splice(i, 1);
              break;
            }
          }
        },

        /**
         * Refresh event listeners UNUSED
         * @memberof hs.legend.controller
         * @function refresh
         */
        refresh: function () {},

        isLegendable: service.isLegendable,
      });

      function init() {
        map = OlMap.map;
        map.getLayers().on('add', layerAdded);
        map.getLayers().on('remove', (e) => {
          $scope.removeLayerFromLegends(e.element);
        });
        map.getLayers().forEach((lyr) => {
          layerAdded({
            element: lyr,
          });
        });
      }

      /**
       * (PRIVATE) Callback function for adding layer to map, add layers legend
       * @memberof hs.legend.controller
       * @function layerAdded
       * @param {Object} e Event object, should have element property
       */
      function layerAdded(e) {
        $scope.addLayerToLegends(e.element);
      }

      function layerVisibilityChanged(e) {
        for (let i = 0; i < $scope.layerDescriptors.length; i++) {
          if ($scope.layerDescriptors[i].lyr == e.target) {
            $scope.layerDescriptors[i].visible = e.target.getVisible();
            break;
          }
        }
      }

      OlMap.loaded().then(init);

      $scope.$emit('scope_loaded', 'Legend');
    },
  ],
};
<commit_msg>Follow layer source params change and update legend<commit_after>export default {
  template: [
    'config',
    (config) => {
      if (config.design == 'md') {
        return require('./partials/legendmd.html');
      } else {
        return require('./partials/legend.html');
      }
    },
  ],
  controller: [
    '$scope',
    'hs.map.service',
    'hs.legend.service',
    function ($scope, OlMap, service) {
      let map;

      angular.extend($scope, {
        layerDescriptors: [],

        /**
         * Add selected layer to the list of layers in legend (with event listener
         * to display/hide legend item when layer visibility change)
         *
         * @memberof hs.legend.controller
         * @function addLayerToLegends
         * @param {object} layer Layer to add legend for
         */
        addLayerToLegends: function (layer) {
          const descriptor = service.getLayerLegendDescriptor(layer);
          if (descriptor) {
            $scope.layerDescriptors.push(descriptor);
            layer.on('change:visible', layerVisibilityChanged);
            layer.getSource().on('change', layerSourcePropChanged);
          }
        },

        /**
         * Check if there is any visible layer
         *
         * @memberof hs.legend.controller
         * @returns {boolean} Returns true if no layers with legend exist
         * @function noLayerExists
         */
        noLayerExists: function () {
          const visibleLayers = $scope.layerDescriptors.filter(
            (check) => check.visible
          );
          return visibleLayers.length == 0;
        },

        /**
         * Remove selected layer from legend items
         *
         * @memberof hs.legend.controller
         * @function removeLayerFromLegends
         * @param {Ol.layer} layer Layer to remove from legend
         */
        removeLayerFromLegends: function (layer) {
          for (let i = 0; i < $scope.layerDescriptors.length; i++) {
            if ($scope.layerDescriptors[i].lyr == layer) {
              $scope.layerDescriptors.splice(i, 1);
              break;
            }
          }
        },

        /**
         * Refresh event listeners UNUSED
         *
         * @memberof hs.legend.controller
         * @function refresh
         */
        refresh: function () {},

        isLegendable: service.isLegendable,
      });

      /**
       *
       */
      function init() {
        map = OlMap.map;
        map.getLayers().on('add', layerAdded);
        map.getLayers().on('remove', (e) => {
          $scope.removeLayerFromLegends(e.element);
        });
        map.getLayers().forEach((lyr) => {
          layerAdded({
            element: lyr,
          });
        });
      }

      /**
       * (PRIVATE) Callback function for adding layer to map, add layers legend
       *
       * @memberof hs.legend.controller
       * @function layerAdded
       * @param {object} e Event object, should have element property
       */
      function layerAdded(e) {
        $scope.addLayerToLegends(e.element);
      }

      /**
       * @param e event description
       */
      function layerVisibilityChanged(e) {
        const descriptor = findLayerDescriptor(e.target);
        if (descriptor) {
          descriptor.visible = e.target.getVisible();
        }
      }

      /**
       * @param e event description
       */
      function layerSourcePropChanged(e) {
        const descriptor = findLayerDescriptorBySource(e.target);
        if (descriptor) {
          const newDescriptor = service.getLayerLegendDescriptor(
            descriptor.lyr
          );

          if (
            newDescriptor.subLayerLegends != descriptor.subLayerLegends ||
            newDescriptor.title != descriptor.title
          ) {
            $scope.layerDescriptors[
              $scope.layerDescriptors.indexOf(descriptor)
            ] = newDescriptor;
          }
        }
      }

      /**
       * Finds layer descriptor for openlayers layer
       *
       * @returns {object} Object describing the legend
       * @param {ol/layer} layer OpenLayers layer
       */
      function findLayerDescriptor(layer) {
        const found = $scope.layerDescriptors.filter((ld) => ld.lyr == layer);
        if (found.length > 0) {
          return found[0];
        }
      }

      /**
       * @param source
       */
      function findLayerDescriptorBySource(source) {
        const found = $scope.layerDescriptors.filter(
          (ld) => ld.lyr.getSource() == source
        );
        if (found.length > 0) {
          return found[0];
        }
      }

      OlMap.loaded().then(init);

      $scope.$emit('scope_loaded', 'Legend');
    },
  ],
};
<|endoftext|>